create space model

This commit is contained in:
hannathkadher
2025-01-08 19:04:08 +04:00
parent 08f322165e
commit 6b79254a89
18 changed files with 477 additions and 150 deletions

View File

@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/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/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'; import 'package:syncrow_web/pages/device_managment/sos/bloc/sos_device_bloc.dart';
class SOSBatchControlView extends StatelessWidget { class SOSBatchControlView extends StatelessWidget {

View File

@ -7,21 +7,49 @@ class AssignTagModelBloc
extends Bloc<AssignTagModelEvent, AssignTagModelState> { extends Bloc<AssignTagModelEvent, AssignTagModelState> {
AssignTagModelBloc() : super(AssignTagModelInitial()) { AssignTagModelBloc() : super(AssignTagModelInitial()) {
on<InitializeTagModels>((event, emit) { on<InitializeTagModels>((event, emit) {
final tags = event.initialTags?.isNotEmpty == true final initialTags = event.initialTags ?? [];
? event.initialTags!
: event.addedProducts
.expand((selectedProduct) => List.generate(
selectedProduct.count,
(index) => TagModel(
tag: '',
product: selectedProduct.product,
location: 'None',
),
))
.toList();
emit( final existingTagCounts = <String, int>{};
AssignTagModelLoaded(tags: tags, isSaveEnabled: _validateTags(tags))); for (var tag in initialTags) {
if (tag.product != null) {
existingTagCounts[tag.product!.uuid] =
(existingTagCounts[tag.product!.uuid] ?? 0) + 1;
}
}
final allTags = <TagModel>[];
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<UpdateTag>((event, emit) { on<UpdateTag>((event, emit) {

View File

@ -1,13 +1,51 @@
import 'package:flutter_bloc/flutter_bloc.dart'; 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_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/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/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 class CreateSpaceModelBloc
extends Bloc<CreateSpaceModelEvent, CreateSpaceModelState> { extends Bloc<CreateSpaceModelEvent, CreateSpaceModelState> {
SpaceTemplateModel? _space; SpaceTemplateModel? _space;
CreateSpaceModelBloc() : super(CreateSpaceModelInitial()) { final SpaceModelManagementApi _api;
CreateSpaceModelBloc(this._api) : super(CreateSpaceModelInitial()) {
on<CreateSpaceTemplate>((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<LoadSpaceTemplate>((event, emit) { on<LoadSpaceTemplate>((event, emit) {
emit(CreateSpaceModelLoading()); emit(CreateSpaceModelLoading());
Future.delayed(const Duration(seconds: 1), () { Future.delayed(const Duration(seconds: 1), () {
@ -25,24 +63,27 @@ class CreateSpaceModelBloc
}); });
on<UpdateSpaceTemplateName>((event, emit) { on<UpdateSpaceTemplateName>((event, emit) {
if (_space != null) { final currentState = state;
_space = _space!.copyWith(modelName: event.name); // Use copyWith for immutability
emit(CreateSpaceModelLoaded(_space!)); if (currentState is CreateSpaceModelLoaded) {
final updatedSpaceModel =
currentState.space.copyWith(modelName: event.name);
emit(CreateSpaceModelLoaded(updatedSpaceModel));
} else { } else {
emit(CreateSpaceModelError("Space template not initialized")); emit(CreateSpaceModelError("Space template not initialized"));
} }
}); });
on<AddSubspacesToSpaceTemplate>((event, emit) { on<AddSubspacesToSpaceTemplate>((event, emit) {
if (_space != null) { final currentState = state;
final updatedSpace = _space!.copyWith(
if (currentState is CreateSpaceModelLoaded) {
final updatedSpace = currentState.space.copyWith(
subspaceModels: [ subspaceModels: [
...(_space!.subspaceModels ?? []), ...(_space!.subspaceModels ?? []),
...event.subspaces, ...event.subspaces,
], ],
); );
_space = updatedSpace;
emit(CreateSpaceModelLoaded(updatedSpace)); emit(CreateSpaceModelLoaded(updatedSpace));
} else { } else {
emit(CreateSpaceModelError("Space template not initialized")); emit(CreateSpaceModelError("Space template not initialized"));

View File

@ -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/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/subspace_template_model.dart';
abstract class CreateSpaceModelEvent {} abstract class CreateSpaceModelEvent extends Equatable {
const CreateSpaceModelEvent();
@override
List<Object> get props => [];
}
class LoadSpaceTemplate extends CreateSpaceModelEvent {} class LoadSpaceTemplate extends CreateSpaceModelEvent {}
@ -11,6 +17,17 @@ class UpdateSpaceTemplate extends CreateSpaceModelEvent {
UpdateSpaceTemplate(this.spaceTemplate); UpdateSpaceTemplate(this.spaceTemplate);
} }
class CreateSpaceTemplate extends CreateSpaceModelEvent {
final SpaceTemplateModel spaceTemplate;
const CreateSpaceTemplate({
required this.spaceTemplate,
});
@override
List<Object> get props => [spaceTemplate];
}
class UpdateSpaceTemplateName extends CreateSpaceModelEvent { class UpdateSpaceTemplateName extends CreateSpaceModelEvent {
final String name; final String name;

View File

@ -1,6 +1,12 @@
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/space_template_model.dart';
abstract class CreateSpaceModelState {} abstract class CreateSpaceModelState extends Equatable {
const CreateSpaceModelState();
@override
List<Object> get props => [];
}
class CreateSpaceModelInitial extends CreateSpaceModelState {} class CreateSpaceModelInitial extends CreateSpaceModelState {}

View File

@ -0,0 +1,47 @@
import 'dart:convert';
class TagBodyModel {
late String uuid;
late String tag;
late final String? productUuid;
Map<String, dynamic> toJson() {
return {
'uuid': uuid,
'tag': tag,
'productUuid': productUuid,
};
}
@override
String toString() {
return toJson().toString();
}
}
class CreateSubspaceTemplateModel {
late String subspaceName;
late List<TagBodyModel>? tags;
}
class CreateSpaceTemplateBodyModel {
final String modelName;
final List<dynamic>? tags;
final List<dynamic>? subspaceModels;
CreateSpaceTemplateBodyModel({
required this.modelName,
this.tags,
this.subspaceModels,
});
Map<String, dynamic> toJson() {
return {
'modelName': modelName,
'tags': tags,
'subspaceModels': subspaceModels,
};
}
}

View File

@ -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/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/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_model.dart';
import 'package:syncrow_web/utils/constants/action_enum.dart'; import 'package:syncrow_web/utils/constants/action_enum.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
class SpaceTemplateModel { class SpaceTemplateModel extends Equatable {
final String? uuid; final String? uuid;
String modelName; String modelName;
List<SubspaceTemplateModel>? subspaceModels; List<SubspaceTemplateModel>? subspaceModels;
final List<TagModel>? tags; final List<TagModel>? tags;
String internalId; String internalId;
@override
List<Object?> get props => [modelName, subspaceModels];
SpaceTemplateModel({ SpaceTemplateModel({
this.uuid, this.uuid,
String? internalId, String? internalId,
@ -26,9 +30,10 @@ class SpaceTemplateModel {
uuid: json['uuid'] ?? '', uuid: json['uuid'] ?? '',
internalId: internalId, internalId: internalId,
modelName: json['modelName'] ?? '', modelName: json['modelName'] ?? '',
subspaceModels: (json['subspaceModels'] as List) subspaceModels: (json['subspaceModels'] as List<dynamic>?)
.map((item) => SubspaceTemplateModel.fromJson(item)) ?.map((e) => SubspaceTemplateModel.fromJson(e))
.toList(), .toList() ??
[],
tags: (json['tags'] as List) tags: (json['tags'] as List)
.map((item) => TagModel.fromJson(item)) .map((item) => TagModel.fromJson(item))
.toList(), .toList(),

View File

@ -1,5 +1,5 @@
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.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/create_space_template_body_model.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
class TagModel { class TagModel {
@ -50,3 +50,12 @@ class TagModel {
}; };
} }
} }
extension TagModelExtensions on TagModel {
TagBodyModel toTagBodyModel() {
return TagBodyModel()
..uuid = uuid ?? ''
..tag = tag ?? ''
..productUuid = product?.uuid;
}
}

View File

@ -19,73 +19,83 @@ class SpaceModelPage extends StatelessWidget {
backgroundColor: ColorsManager.whiteColors, backgroundColor: ColorsManager.whiteColors,
body: Padding( body: Padding(
padding: const EdgeInsets.fromLTRB(20.0, 16.0, 16.0, 16.0), padding: const EdgeInsets.fromLTRB(20.0, 16.0, 16.0, 16.0),
child: GridView.builder( child: Column(
//clipBehavior: Clip.none, crossAxisAlignment: CrossAxisAlignment.stretch,
shrinkWrap: false, children: [
physics: const AlwaysScrollableScrollPhysics(), Expanded(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( child: GridView.builder(
crossAxisCount: 3, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 13.0, crossAxisCount: 3,
mainAxisSpacing: 13.0, crossAxisSpacing: 10.0,
childAspectRatio: calculateChildAspectRatio(context), 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: 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
),
),
),
), ),
); 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]; Widget _buildAddContainer() {
return SpaceModelCardWidget(model: model); 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 calculateChildAspectRatio(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width; double screenWidth = MediaQuery.of(context).size.width;
// Adjust the aspect ratio based on the screen width
if (screenWidth > 1600) { if (screenWidth > 1600) {
return 4.0; // For large screens return 3;
} }
if (screenWidth > 1200) { if (screenWidth > 1200) {
return 3.2; // For large screens return 5;
} else if (screenWidth > 800) { } else if (screenWidth > 800) {
return 3.0; // For medium screens return 5;
} else { } else {
return 2.0; // For small screens return 6.0;
} }
} }

View File

@ -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_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/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/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/tag_chips_display_widget.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_model_create_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 'package:syncrow_web/utils/color_manager.dart';
import '../../models/subspace_template_model.dart'; import '../../models/subspace_template_model.dart';
@ -26,31 +26,45 @@ class CreateSpaceModelDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final SpaceModelManagementApi _spaceModelApi = SpaceModelManagementApi();
final screenWidth = MediaQuery.of(context).size.width; final screenWidth = MediaQuery.of(context).size.width;
List<SubspaceTemplateModel>? subspaces = spaceModel?.subspaceModels ?? []; List<SubspaceTemplateModel>? subspaces = spaceModel?.subspaceModels ?? [];
final TextEditingController spaceNameController = TextEditingController( final TextEditingController spaceNameController = TextEditingController(
text: spaceModel?.modelName ?? '', text: spaceModel?.modelName ?? '',
); );
return AlertDialog( return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
backgroundColor: ColorsManager.whiteColors, backgroundColor: ColorsManager.whiteColors,
content: SizedBox( content: SizedBox(
width: screenWidth * 0.3, width: screenWidth * 0.3,
child: BlocProvider( child: BlocProvider(
create: (_) { create: (_) {
final bloc = CreateSpaceModelBloc(); final bloc = CreateSpaceModelBloc(_spaceModelApi);
if (spaceModel != null) { if (spaceModel != null) {
bloc.add(UpdateSpaceTemplate(spaceModel!)); bloc.add(UpdateSpaceTemplate(spaceModel!));
} else { } else {
bloc.add(UpdateSpaceTemplate(SpaceTemplateModel( bloc.add(UpdateSpaceTemplate(SpaceTemplateModel(
modelName: '', modelName: '',
subspaceModels: [], subspaceModels: [],
))); )));
} }
return bloc;
}, spaceNameController.addListener(() {
child: BlocBuilder<CreateSpaceModelBloc, CreateSpaceModelState>( bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text));
builder: (context, state) { });
return bloc;
},
child: BlocBuilder<CreateSpaceModelBloc, CreateSpaceModelState>(
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( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -66,6 +80,11 @@ class CreateSpaceModelDialog extends StatelessWidget {
width: screenWidth * 0.25, width: screenWidth * 0.25,
child: TextField( child: TextField(
controller: spaceNameController, controller: spaceNameController,
onChanged: (value) {
context
.read<CreateSpaceModelBloc>()
.add(UpdateSpaceTemplateName(name: value));
},
style: const TextStyle(color: ColorsManager.blackColor), style: const TextStyle(color: ColorsManager.blackColor),
decoration: InputDecoration( decoration: InputDecoration(
filled: true, filled: true,
@ -85,11 +104,12 @@ class CreateSpaceModelDialog extends StatelessWidget {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
SubspaceModelCreate(context, subspaces: subspaces), SubspaceModelCreate(context,
subspaces: state.space.subspaceModels ?? []),
const SizedBox(height: 10), const SizedBox(height: 10),
TagChipDisplay(context, TagChipDisplay(context,
screenWidth: screenWidth, screenWidth: screenWidth,
spaceModel: spaceModel, spaceModel: updatedSpaceModel,
products: products, products: products,
subspaces: subspaces, subspaces: subspaces,
allTags: allTags, allTags: allTags,
@ -109,8 +129,14 @@ class CreateSpaceModelDialog extends StatelessWidget {
Expanded( Expanded(
child: DefaultButton( child: DefaultButton(
onPressed: () { onPressed: () {
// Return data when OK is pressed final updatedSpaceTemplate =
Navigator.of(context).pop(subspaces); updatedSpaceModel.copyWith(
modelName: spaceNameController.text.trim(),
);
context.read<CreateSpaceModelBloc>().add(
CreateSpaceTemplate(
spaceTemplate: updatedSpaceTemplate),
);
}, },
backgroundColor: ColorsManager.secondaryColor, backgroundColor: ColorsManager.secondaryColor,
borderRadius: 10, 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...'));
},
),
),
),
); );
} }
} }

View File

@ -10,7 +10,8 @@ import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_spac
class SubspaceModelCreate extends StatelessWidget { class SubspaceModelCreate extends StatelessWidget {
final List<SubspaceTemplateModel> subspaces; final List<SubspaceTemplateModel> subspaces;
const SubspaceModelCreate(BuildContext context, { const SubspaceModelCreate(
BuildContext context, {
Key? key, Key? key,
required this.subspaces, required this.subspaces,
}) : super(key: key); }) : super(key: key);
@ -26,6 +27,8 @@ class SubspaceModelCreate extends StatelessWidget {
overlayColor: ColorsManager.transparentColor, overlayColor: ColorsManager.transparentColor,
), ),
onPressed: () async { onPressed: () async {
Navigator.of(context).pop();
final result = await showDialog<List<SubspaceTemplateModel>>( final result = await showDialog<List<SubspaceTemplateModel>>(
barrierDismissible: false, barrierDismissible: false,
context: context, context: context,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.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/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/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/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_model.dart';
@ -29,7 +30,8 @@ class TagChipDisplay extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return (spaceModel?.subspaceModels?.isNotEmpty == true || spaceModel?.tags?.isNotEmpty == true || return (spaceModel?.subspaceModels?.isNotEmpty == true ||
spaceModel?.tags?.isNotEmpty == true ||
spaceModel?.subspaceModels spaceModel?.subspaceModels
?.any((subspace) => subspace.tags?.isNotEmpty == true) == ?.any((subspace) => subspace.tags?.isNotEmpty == true) ==
true) true)
@ -60,8 +62,7 @@ class TagChipDisplay extends StatelessWidget {
width: 24, width: 24,
height: 24, height: 24,
child: SvgPicture.asset( child: SvgPicture.asset(
entry.key.icon ?? entry.key.icon ?? 'assets/icons/gateway.svg',
'assets/default_icon.svg', // Provide a default asset path if null
fit: BoxFit.contain, fit: BoxFit.contain,
), ),
), ),
@ -71,19 +72,19 @@ class TagChipDisplay extends StatelessWidget {
color: ColorsManager.spaceColor, color: ColorsManager.spaceColor,
), ),
), ),
backgroundColor: backgroundColor: Colors.white,
Colors.white, // Chip background color
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius: BorderRadius.circular(16),
BorderRadius.circular(16), // Rounded chip
side: const BorderSide( side: const BorderSide(
color: ColorsManager.spaceColor, // Border color color: ColorsManager.spaceColor,
), ),
), ),
), ),
), ),
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
Navigator.of(context).pop();
await showDialog<bool>( await showDialog<bool>(
barrierDismissible: false, barrierDismissible: false,
context: context, context: context,
@ -92,6 +93,10 @@ class TagChipDisplay extends StatelessWidget {
subspaces: subspaces, subspaces: subspaces,
allTags: allTags, allTags: allTags,
spaceName: spaceNameController.text, spaceName: spaceNameController.text,
spaceTagModels: spaceModel?.tags,
initialSelectedProducts:
_createInitialSelectedProducts(
spaceModel?.tags, spaceModel?.subspaceModels),
), ),
); );
// Edit action // Edit action
@ -117,6 +122,8 @@ class TagChipDisplay extends StatelessWidget {
) )
: TextButton( : TextButton(
onPressed: () async { onPressed: () async {
Navigator.of(context).pop();
final result = await showDialog<bool>( final result = await showDialog<bool>(
barrierDismissible: false, barrierDismissible: false,
context: context, context: context,
@ -148,4 +155,42 @@ class TagChipDisplay extends StatelessWidget {
} }
return groupedTags; return groupedTags;
} }
List<SelectedProduct> _createInitialSelectedProducts(
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces) {
final Map<ProductModel, int> 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();
}
} }

View File

@ -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/product_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/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/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/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/action_button_widget.dart';
import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/scrollable_grid_view_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<List<SelectedProduct>>? onProductsSelected; final ValueChanged<List<SelectedProduct>>? onProductsSelected;
final List<SelectedProduct>? initialSelectedProducts; final List<SelectedProduct>? initialSelectedProducts;
final List<SubspaceTemplateModel>? subspaces; final List<SubspaceTemplateModel>? subspaces;
final List<TagModel>? spaceTagModels;
final List<String>? allTags; final List<String>? allTags;
final String spaceName; final String spaceName;
@ -25,8 +27,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
this.onProductsSelected, this.onProductsSelected,
this.subspaces, this.subspaces,
this.allTags, this.allTags,
required this.spaceName this.spaceTagModels,
}); required this.spaceName});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -89,6 +91,9 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
addedProducts: currentState, addedProducts: currentState,
allTags: allTags, allTags: allTags,
spaceName: spaceName, spaceName: spaceName,
initialTags: generateInitialTags(
spaceTagModels: spaceTagModels,
subspaces: subspaces),
), ),
); );
} }
@ -100,4 +105,29 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
), ),
)); ));
} }
List<TagModel> generateInitialTags({
List<TagModel>? spaceTagModels,
List<SubspaceTemplateModel>? subspaces,
}) {
final List<TagModel> 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;
}
} }

View File

@ -8,11 +8,13 @@ import 'package:syncrow_web/pages/spaces_management/tag_model/widgets/device_typ
class ScrollableGridViewWidget extends StatelessWidget { class ScrollableGridViewWidget extends StatelessWidget {
final List<ProductModel>? products; final List<ProductModel>? products;
final int crossAxisCount; final int crossAxisCount;
final List<SelectedProduct>? initialProductCounts;
const ScrollableGridViewWidget({ const ScrollableGridViewWidget({
super.key, super.key,
required this.products, required this.products,
required this.crossAxisCount, required this.crossAxisCount,
this.initialProductCounts,
}); });
@override @override
@ -36,9 +38,13 @@ class ScrollableGridViewWidget extends StatelessWidget {
itemCount: products?.length ?? 0, itemCount: products?.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final product = products![index]; final product = products![index];
final initialProductCount = _findInitialProductCount(product);
return DeviceTypeTileWidget( return DeviceTypeTileWidget(
product: product, 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;
}
} }

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:syncrow_web/services/api/http_interceptor.dart'; import 'package:syncrow_web/services/api/http_interceptor.dart';
import 'package:syncrow_web/services/locator.dart'; import 'package:syncrow_web/services/locator.dart';
@ -42,22 +44,30 @@ class HTTPService {
} }
} }
Future<T> post<T>( Future<T> post<T>({
{required String path, required String path,
Map<String, dynamic>? queryParameters, Map<String, dynamic>? queryParameters,
Options? options, Options? options,
dynamic body, dynamic body,
bool showServerMessage = true, bool showServerMessage = true,
required T Function(dynamic) expectedResponseModel}) async { required T Function(dynamic) expectedResponseModel,
}) async {
try { 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( final response = await client.post(
path, path,
data: body, data: body,
queryParameters: queryParameters, queryParameters: queryParameters,
options: options, options: options,
); );
print("POST Response: ${response.data.toString()}");
return expectedResponseModel(response.data); return expectedResponseModel(response.data);
} catch (error) { } catch (error) {
print("POST Error: $error");
rethrow; rethrow;
} }
} }

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; 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/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_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/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; 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/pages/spaces_management/space_model/models/space_template_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';
@ -34,4 +35,23 @@ class SpaceModelManagementApi {
return []; return [];
} }
} }
Future<SpaceTemplateModel?> 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;
}
}
} }

View File

@ -99,4 +99,5 @@ abstract class ApiEndpoints {
//space model //space model
static const String listSpaceModels = '/projects/{projectId}/space-models'; static const String listSpaceModels = '/projects/{projectId}/space-models';
static const String createSpaceModel = '/projects/{projectId}/space-models';
} }