edit flow

This commit is contained in:
hannathkadher
2025-01-20 21:47:22 +04:00
parent 2f6bd31aa2
commit eb53671e3a
11 changed files with 315 additions and 172 deletions

View File

@ -3,8 +3,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_event.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_event.dart';
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart';
class AssignTagBloc class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
extends Bloc<AssignTagEvent, AssignTagState> {
AssignTagBloc() : super(AssignTagInitial()) { AssignTagBloc() : super(AssignTagInitial()) {
on<InitializeTags>((event, emit) { on<InitializeTags>((event, emit) {
final initialTags = event.initialTags ?? []; final initialTags = event.initialTags ?? [];
@ -40,7 +39,7 @@ class AssignTagBloc
(index) => Tag( (index) => Tag(
tag: '', tag: '',
product: selectedProduct.product, product: selectedProduct.product,
location: 'None', location: 'Main Space',
), ),
)); ));
} }
@ -55,8 +54,7 @@ class AssignTagBloc
on<UpdateTagEvent>((event, emit) { on<UpdateTagEvent>((event, emit) {
final currentState = state; final currentState = state;
if (currentState is AssignTagLoaded && if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
currentState.tags.isNotEmpty) {
final tags = List<Tag>.from(currentState.tags); final tags = List<Tag>.from(currentState.tags);
tags[event.index].tag = event.tag; tags[event.index].tag = event.tag;
emit(AssignTagLoaded( emit(AssignTagLoaded(
@ -70,8 +68,7 @@ class AssignTagBloc
on<UpdateLocation>((event, emit) { on<UpdateLocation>((event, emit) {
final currentState = state; final currentState = state;
if (currentState is AssignTagLoaded && if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
currentState.tags.isNotEmpty) {
final tags = List<Tag>.from(currentState.tags); final tags = List<Tag>.from(currentState.tags);
// Use copyWith for immutability // Use copyWith for immutability
@ -88,8 +85,7 @@ class AssignTagBloc
on<ValidateTags>((event, emit) { on<ValidateTags>((event, emit) {
final currentState = state; final currentState = state;
if (currentState is AssignTagLoaded && if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
currentState.tags.isNotEmpty) {
final tags = List<Tag>.from(currentState.tags); final tags = List<Tag>.from(currentState.tags);
emit(AssignTagLoaded( emit(AssignTagLoaded(
@ -103,8 +99,7 @@ class AssignTagBloc
on<DeleteTag>((event, emit) { on<DeleteTag>((event, emit) {
final currentState = state; final currentState = state;
if (currentState is AssignTagLoaded && if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
currentState.tags.isNotEmpty) {
final updatedTags = List<Tag>.from(currentState.tags) final updatedTags = List<Tag>.from(currentState.tags)
..remove(event.tagToDelete); ..remove(event.tagToDelete);

View File

@ -224,7 +224,7 @@ class AssignTagDialog extends StatelessWidget {
DataCell( DataCell(
DropdownButtonHideUnderline( DropdownButtonHideUnderline(
child: DropdownButton<String>( child: DropdownButton<String>(
value: tag.location ?? 'None', value: tag.location ?? 'Main',
dropdownColor: ColorsManager dropdownColor: ColorsManager
.whiteColors, // Dropdown background .whiteColors, // Dropdown background
style: const TextStyle( style: const TextStyle(
@ -232,9 +232,9 @@ class AssignTagDialog extends StatelessWidget {
.black), // Style for selected text .black), // Style for selected text
items: [ items: [
const DropdownMenuItem<String>( const DropdownMenuItem<String>(
value: 'None', value: 'Main Space',
child: Text( child: Text(
'None', 'Main Space',
style: TextStyle( style: TextStyle(
color: ColorsManager color: ColorsManager
.textPrimaryColor), .textPrimaryColor),

View File

@ -40,7 +40,7 @@ class AssignTagModelBloc
(index) => TagModel( (index) => TagModel(
tag: '', tag: '',
product: selectedProduct.product, product: selectedProduct.product,
location: 'None', location: 'Main Space',
), ),
)); ));
} }
@ -123,6 +123,7 @@ class AssignTagModelBloc
bool _validateTags(List<TagModel> tags) { bool _validateTags(List<TagModel> tags) {
if (tags.isEmpty) { if (tags.isEmpty) {
print("tags empty");
return false; return false;
} }
final uniqueTags = tags.map((tag) => tag.tag?.trim() ?? '').toSet(); final uniqueTags = tags.map((tag) => tag.tag?.trim() ?? '').toSet();

View File

@ -11,6 +11,7 @@ import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assig
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.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/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class AssignTagModelsDialog extends StatelessWidget { class AssignTagModelsDialog extends StatelessWidget {
@ -40,8 +41,11 @@ class AssignTagModelsDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<String> locations = final List<String> locations = (subspaces ?? [])
(subspaces ?? []).map((subspace) => subspace.subspaceName).toList(); .map((subspace) => subspace.subspaceName)
.toList()
..add('Main Space');
return BlocProvider( return BlocProvider(
create: (_) => AssignTagModelBloc() create: (_) => AssignTagModelBloc()
..add(InitializeTagModels( ..add(InitializeTagModels(
@ -173,7 +177,8 @@ class AssignTagModelsDialog extends StatelessWidget {
width: double width: double
.infinity, // Ensure full width for dropdown .infinity, // Ensure full width for dropdown
child: DialogTextfieldDropdown( child: DialogTextfieldDropdown(
items: availableTags ?? [], items: availableTags,
initialValue: tag.tag,
onSelected: (value) { onSelected: (value) {
controller.text = value; controller.text = value;
context context
@ -223,26 +228,55 @@ class AssignTagModelsDialog extends StatelessWidget {
children: [ children: [
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: CancelButton( child: Builder(
label: 'Add New Device', builder: (buttonContext) => CancelButton(
onPressed: () async { label: 'Add New Device',
Navigator.of(context).pop(); onPressed: () async {
final assignedTags = <TagModel>{}; Navigator.of(context).pop();
for (var tag in state.tags) {
if (tag.location == null || subspaces == null) { for (var tag in state.tags) {
continue; if (tag.location == null || subspaces == null) {
} continue;
for (var subspace in subspaces!) {
if (tag.location == subspace.subspaceName) {
subspace.tags ??= [];
subspace.tags!.add(tag);
assignedTags.add(tag);
break;
} }
final previousTagSubspace =
checkTagExistInSubspace(tag, subspaces ?? []);
if (tag.location == 'Main Space') {
removeTagFromSubspace(tag, previousTagSubspace);
} else if (tag.location !=
previousTagSubspace?.subspaceName) {
removeTagFromSubspace(tag, previousTagSubspace);
moveToNewSubspace(tag, subspaces ?? []);
state.tags.removeWhere(
(t) => t.internalId == tag.internalId);
} else {
updateTagInSubspace(tag, previousTagSubspace);
state.tags.removeWhere(
(t) => t.internalId == tag.internalId);
}
await showDialog<bool>(
barrierDismissible: false,
context:
Navigator.of(context, rootNavigator: true)
.context,
builder: (context) => AddDeviceTypeModelWidget(
products: products,
subspaces: subspaces,
isCreate: false,
initialSelectedProducts: addedProducts,
allTags: allTags,
spaceName: spaceName,
spaceTagModels: state.tags,
onUpdate: (tags, subspaces) {
onUpdate?.call(state.tags, subspaces);
},
),
);
} }
} },
state.tags.removeWhere(assignedTags.contains); ),
},
), ),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
@ -256,23 +290,38 @@ class AssignTagModelsDialog extends StatelessWidget {
onPressed: state.isSaveEnabled onPressed: state.isSaveEnabled
? () async { ? () async {
Navigator.of(context).pop(); Navigator.of(context).pop();
final assignedTags = <TagModel>{};
for (var tag in state.tags) { for (var tag in state.tags) {
if (tag.location == null || if (tag.location == null ||
subspaces == null) { subspaces == null) {
continue; continue;
} }
for (var subspace in subspaces!) {
if (tag.location == subspace.subspaceName) { final previousTagSubspace =
subspace.tags ??= []; checkTagExistInSubspace(
subspace.tags!.add(tag); tag, subspaces ?? []);
assignedTags.add(tag);
break; if (tag.location == 'Main Space') {
} removeTagFromSubspace(
tag, previousTagSubspace);
} else if (tag.location !=
previousTagSubspace?.subspaceName) {
removeTagFromSubspace(
tag, previousTagSubspace);
moveToNewSubspace(tag, subspaces ?? []);
state.tags.removeWhere(
(t) => t.internalId == tag.internalId);
} else {
updateTagInSubspace(
tag, previousTagSubspace);
state.tags.removeWhere(
(t) => t.internalId == tag.internalId);
} }
} }
state.tags.removeWhere(assignedTags.contains); print("tryinh yo save");
onUpdate!(state.tags,subspaces);
onUpdate?.call(state.tags, subspaces);
} }
: null, : null,
child: const Text('Save'), child: const Text('Save'),
@ -302,4 +351,40 @@ class AssignTagModelsDialog extends StatelessWidget {
.contains(tagValue)) .contains(tagValue))
.toList(); .toList();
} }
void removeTagFromSubspace(TagModel tag, SubspaceTemplateModel? subspace) {
subspace?.tags?.removeWhere((t) => t.internalId == tag.internalId);
}
SubspaceTemplateModel? checkTagExistInSubspace(
TagModel tag, List<SubspaceTemplateModel>? subspaces) {
if (subspaces == null) return null;
for (var subspace in subspaces) {
if (subspace.tags == null) return null;
for (var t in subspace.tags!) {
if (tag.internalId == t.internalId) return subspace;
}
}
return null;
}
void moveToNewSubspace(TagModel tag, List<SubspaceTemplateModel> subspaces) {
final targetSubspace = subspaces
.firstWhere((subspace) => subspace.subspaceName == tag.location);
targetSubspace.tags ??= [];
if (targetSubspace.tags?.any((t) => t.internalId == tag.internalId) !=
true) {
targetSubspace.tags?.add(tag);
}
}
void updateTagInSubspace(TagModel tag, SubspaceTemplateModel? subspace) {
final currentTag = subspace?.tags?.firstWhere(
(t) => t.internalId == tag.internalId,
);
if (currentTag != null) {
currentTag.tag = tag.tag;
}
}
} }

View File

@ -17,15 +17,19 @@ class TagHelper {
if (subspaces != null) { if (subspaces != null) {
for (var subspace in subspaces) { for (var subspace in subspaces) {
if (subspace.tags != null) { if (subspace.tags != null) {
initialTags.addAll( for (var existingTag in subspace.tags!) {
subspace.tags!.map( initialTags.addAll(
(tag) => tag.copyWith(location: subspace.subspaceName), subspace.tags!.map(
), (tag) => tag.copyWith(
); location: subspace.subspaceName,
internalId: existingTag.internalId,
tag: existingTag.tag),
),
);
}
} }
} }
} }
return initialTags; return initialTags;
} }

View File

@ -3,6 +3,7 @@ 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_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/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/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/services/space_model_mang_api.dart'; import 'package:syncrow_web/services/space_model_mang_api.dart';
@ -67,36 +68,102 @@ class CreateSpaceModelBloc
_space = event.spaceTemplate; _space = event.spaceTemplate;
emit(CreateSpaceModelLoaded(_space!)); emit(CreateSpaceModelLoaded(_space!));
}); });
on<AddSubspacesToSpaceTemplate>((event, emit) { on<AddSubspacesToSpaceTemplate>((event, emit) {
final currentState = state; final currentState = state;
if (currentState is CreateSpaceModelLoaded) { if (currentState is CreateSpaceModelLoaded) {
final updatedSpace = currentState.space.copyWith( final eventSubspaceIds =
subspaceModels: [ event.subspaces.map((e) => e.internalId).toSet();
...(_space!.subspaceModels ?? []),
...event.subspaces, // Update or retain subspaces
], final updatedSubspaces = currentState.space.subspaceModels
); ?.where((subspace) =>
eventSubspaceIds.contains(subspace.internalId))
.map((subspace) {
final matchingEventSubspace = event.subspaces.firstWhere(
(e) => e.internalId == subspace.internalId,
orElse: () => subspace,
);
// Update the subspace's tags
final eventTagIds = matchingEventSubspace.tags
?.map((e) => e.internalId)
.toSet() ??
{};
final updatedTags = [
...?subspace.tags?.map<TagModel>((tag) {
final matchingTag =
matchingEventSubspace.tags?.firstWhere(
(e) => e.internalId == tag.internalId,
orElse: () => tag,
);
final isUpdated = matchingTag != tag;
return isUpdated
? tag.copyWith(tag: matchingTag?.tag)
: tag;
}) ??
<TagModel>[],
...?matchingEventSubspace.tags?.where(
(e) =>
subspace.tags
?.every((t) => t.internalId != e.internalId) ??
true,
) ??
<TagModel>[],
];
return subspace.copyWith(
subspaceName: matchingEventSubspace.subspaceName,
tags: updatedTags,
);
}).toList() ??
[];
// Add new subspaces
event.subspaces
.where((e) =>
updatedSubspaces.every((s) => s.internalId != e.internalId))
.forEach((newSubspace) {
updatedSubspaces.add(newSubspace);
});
final updatedSpace =
currentState.space.copyWith(subspaceModels: updatedSubspaces);
emit(CreateSpaceModelLoaded(updatedSpace)); emit(CreateSpaceModelLoaded(updatedSpace));
} else { } else {
emit(CreateSpaceModelError("Space template not initialized")); emit(CreateSpaceModelError("Space template not initialized"));
} }
}); });
on<AddTagsToSpaceTemplate>((event, emit) { on<AddTagsToSpaceTemplate>((event, emit) {
final currentState = state; final currentState = state;
if (currentState is CreateSpaceModelLoaded) { if (currentState is CreateSpaceModelLoaded) {
final updatedTags = currentState.space.copyWith( final eventTagIds = event.tags.map((e) => e.internalId).toSet();
tags: [
...(_space!.tags ?? []), final updatedTags = currentState.space.tags
...event.tags, ?.where((tag) => eventTagIds.contains(tag.internalId))
], .map((tag) {
); final matchingEventTag = event.tags.firstWhere(
emit(CreateSpaceModelLoaded(updatedTags)); (e) => e.internalId == tag.internalId,
orElse: () => tag,
);
return matchingEventTag != tag
? tag.copyWith(tag: matchingEventTag.tag)
: tag;
}).toList() ??
[];
event.tags
.where(
(e) => updatedTags.every((t) => t.internalId != e.internalId))
.forEach((e) {
updatedTags.add(e);
});
emit(CreateSpaceModelLoaded(
currentState.space.copyWith(tags: updatedTags)));
} else { } else {
emit(CreateSpaceModelError("Space template not initialized")); emit(CreateSpaceModelError("Space template not initialized"));
} }
@ -106,7 +173,6 @@ class CreateSpaceModelBloc
final currentState = state; final currentState = state;
if (currentState is CreateSpaceModelLoaded) { if (currentState is CreateSpaceModelLoaded) {
if (event.name.trim().isEmpty) { if (event.name.trim().isEmpty) {
emit(CreateSpaceModelLoaded( emit(CreateSpaceModelLoaded(
currentState.space, currentState.space,
errorMessage: "Model name cannot be empty", errorMessage: "Model name cannot be empty",
@ -114,7 +180,7 @@ class CreateSpaceModelBloc
} else { } else {
final updatedSpaceModel = final updatedSpaceModel =
currentState.space.copyWith(modelName: event.name); currentState.space.copyWith(modelName: event.name);
emit(CreateSpaceModelLoaded(updatedSpaceModel)); emit(CreateSpaceModelLoaded(updatedSpaceModel));
} }
} else { } else {

View File

@ -1,22 +1,28 @@
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:uuid/uuid.dart';
class SubspaceTemplateModel { class SubspaceTemplateModel {
final String? uuid; final String? uuid;
String subspaceName; String subspaceName;
final bool disabled; final bool disabled;
List<TagModel>? tags; List<TagModel>? tags;
String internalId;
SubspaceTemplateModel({ SubspaceTemplateModel({
this.uuid, this.uuid,
required this.subspaceName, required this.subspaceName,
required this.disabled, required this.disabled,
this.tags, this.tags,
}); String? internalId,
}) : internalId = internalId ?? const Uuid().v4();
factory SubspaceTemplateModel.fromJson(Map<String, dynamic> json) { factory SubspaceTemplateModel.fromJson(Map<String, dynamic> json) {
final String internalId = json['internalId'] ?? const Uuid().v4();
return SubspaceTemplateModel( return SubspaceTemplateModel(
uuid: json['uuid'] ?? '', uuid: json['uuid'] ?? '',
subspaceName: json['subspaceName'] ?? '', subspaceName: json['subspaceName'] ?? '',
internalId: internalId,
disabled: json['disabled'] ?? false, disabled: json['disabled'] ?? false,
tags: (json['tags'] as List<dynamic>?) tags: (json['tags'] as List<dynamic>?)
?.map((item) => TagModel.fromJson(item)) ?.map((item) => TagModel.fromJson(item))
@ -33,4 +39,20 @@ class SubspaceTemplateModel {
'tags': tags?.map((e) => e.toJson()).toList() ?? [], 'tags': tags?.map((e) => e.toJson()).toList() ?? [],
}; };
} }
SubspaceTemplateModel copyWith({
String? uuid,
String? subspaceName,
bool? disabled,
List<TagModel>? tags,
String? internalId,
}) {
return SubspaceTemplateModel(
uuid: uuid ?? this.uuid,
subspaceName: subspaceName ?? this.subspaceName,
disabled: disabled ?? this.disabled,
tags: tags ?? this.tags,
internalId: internalId ?? this.internalId,
);
}
} }

View File

@ -30,15 +30,16 @@ class TagModel {
); );
} }
TagModel copyWith({ TagModel copyWith(
String? tag, {String? tag,
ProductModel? product, ProductModel? product,
String? location, String? location,
}) { String? internalId}) {
return TagModel( return TagModel(
tag: tag ?? this.tag, tag: tag ?? this.tag,
product: product ?? this.product, product: product ?? this.product,
location: location ?? this.location, location: location ?? this.location,
internalId: internalId ?? this.internalId,
); );
} }
@ -58,4 +59,4 @@ extension TagModelExtensions on TagModel {
..tag = tag ?? '' ..tag = tag ?? ''
..productUuid = product?.uuid; ..productUuid = product?.uuid;
} }
} }

View File

@ -44,15 +44,15 @@ class CreateSpaceModelDialog extends StatelessWidget {
child: BlocProvider( child: BlocProvider(
create: (_) { create: (_) {
final bloc = CreateSpaceModelBloc(_spaceModelApi); 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: const [], subspaceModels: const [],
))); )));
} }
spaceNameController.addListener(() { spaceNameController.addListener(() {
bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text)); bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text));
}); });
@ -72,7 +72,9 @@ class CreateSpaceModelDialog extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
spaceModel?.uuid == null ? 'Create New Space Model': 'Edit Space Model', spaceModel?.uuid == null
? 'Create New Space Model'
: 'Edit Space Model',
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.headlineLarge .headlineLarge
@ -127,16 +129,18 @@ class CreateSpaceModelDialog extends StatelessWidget {
allTags: allTags, allTags: allTags,
spaceNameController: spaceNameController, spaceNameController: spaceNameController,
onLoad: (tags, subspaces) { onLoad: (tags, subspaces) {
if(subspaces!=null){ if (context.read<CreateSpaceModelBloc>().state
context is CreateSpaceModelLoaded) {
.read<CreateSpaceModelBloc>() if (subspaces != null) {
.add(AddSubspacesToSpaceTemplate(subspaces));
}
if(tags!=null){
context context
.read<CreateSpaceModelBloc>() .read<CreateSpaceModelBloc>()
.add(AddTagsToSpaceTemplate(tags)); .add(AddSubspacesToSpaceTemplate(subspaces));
}
if (tags != null) {
context
.read<CreateSpaceModelBloc>()
.add(AddTagsToSpaceTemplate(tags));
}
} }
}, },
), ),

View File

@ -1,7 +1,8 @@
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/assign_tag_models/views/assign_tag_models_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.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';
@ -53,7 +54,7 @@ class TagChipDisplay extends StatelessWidget {
runSpacing: 8.0, runSpacing: 8.0,
children: [ children: [
// Combine tags from spaceModel and subspaces // Combine tags from spaceModel and subspaces
..._groupTags([ ...TagHelper.groupTags([
...?spaceModel?.tags, ...?spaceModel?.tags,
...?spaceModel?.subspaceModels ...?spaceModel?.subspaceModels
?.expand((subspace) => subspace.tags ?? []) ?.expand((subspace) => subspace.tags ?? [])
@ -84,24 +85,32 @@ class TagChipDisplay extends StatelessWidget {
), ),
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
Navigator.of(context).pop(); // Use the Navigator's context for showDialog
final navigatorContext =
Navigator.of(context).overlay?.context;
await showDialog<bool>( if (navigatorContext != null) {
barrierDismissible: false, await showDialog<bool>(
context: context, barrierDismissible: false,
builder: (context) => AddDeviceTypeModelWidget( context: navigatorContext,
isCreate: false, builder: (context) => AssignTagModelsDialog(
products: products, products: products,
subspaces: subspaces, subspaces: subspaces,
allTags: allTags, allTags: allTags,
spaceName: spaceNameController.text, initialTags: TagHelper.generateInitialTags(
spaceTagModels: spaceModel?.tags, subspaces: subspaces,
initialSelectedProducts: spaceTagModels: spaceModel?.tags ?? []),
_createInitialSelectedProducts( title: 'Edit Device',
spaceModel?.tags, spaceModel?.subspaceModels), addedProducts:
), TagHelper.createInitialSelectedProducts(
); spaceModel?.tags ?? [], subspaces),
// Edit action spaceName: spaceModel?.modelName ?? '',
onUpdate: (tags, subspaces){
print("here");
onLoad?.call(tags, subspaces);}
),
);
}
}, },
child: Chip( child: Chip(
label: const Text( label: const Text(
@ -130,11 +139,7 @@ class TagChipDisplay extends StatelessWidget {
allTags: allTags, allTags: allTags,
spaceName: spaceNameController.text, spaceName: spaceNameController.text,
isCreate: true, isCreate: true,
onLoad: (tags, subspaces) { onLoad: (tags, subspaces) => onLoad?.call(tags, subspaces),
if (onLoad != null) {
onLoad!(tags, subspaces);
}
},
), ),
); );
}, },
@ -147,49 +152,4 @@ class TagChipDisplay extends StatelessWidget {
), ),
); );
} }
Map<ProductModel, int> _groupTags(List<TagModel> tags) {
final Map<ProductModel, int> groupedTags = {};
for (var tag in tags) {
if (tag.product != null) {
groupedTags[tag.product!] = (groupedTags[tag.product!] ?? 0) + 1;
}
}
return groupedTags;
}
List<SelectedProduct> _createInitialSelectedProducts(
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces) {
final Map<ProductModel, int> productCounts = {};
if (tags != null) {
for (var tag in tags) {
if (tag.product != null) {
productCounts[tag.product!] = (productCounts[tag.product!] ?? 0) + 1;
}
}
}
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;
}
}
}
}
}
return productCounts.entries
.map((entry) => SelectedProduct(
productId: entry.key.uuid,
count: entry.value,
productName: entry.key.name ?? 'Unnamed',
product: entry.key,
))
.toList();
}
} }

View File

@ -23,6 +23,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
final bool isCreate; final bool isCreate;
final void Function( final void Function(
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces)? onLoad; List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces)? onLoad;
final void Function(
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces)? onUpdate;
const AddDeviceTypeModelWidget({ const AddDeviceTypeModelWidget({
super.key, super.key,
@ -34,10 +36,18 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
required this.spaceName, required this.spaceName,
required this.isCreate, required this.isCreate,
this.onLoad, this.onLoad,
this.onUpdate,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (spaceTagModels != null) {
for (var tag in spaceTagModels!) {
print(tag.tag);
}
}
final size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
final crossAxisCount = size.width > 1200 final crossAxisCount = size.width > 1200
? 8 ? 8
@ -123,15 +133,12 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
spaceTagModels: spaceTagModels, spaceTagModels: spaceTagModels,
subspaces: subspaces, subspaces: subspaces,
); );
if (isCreate) {
Navigator.of(context).pop();
}
final dialogTitle = initialTags.isNotEmpty final dialogTitle = initialTags.isNotEmpty
? 'Edit Device' ? 'Edit Device'
: 'Assign Tags'; : 'Assign Tags';
Navigator.of(context).pop();
await showDialog<bool>( await showDialog<bool>(
barrierDismissible: false,
context: context, context: context,
builder: (context) => AssignTagModelsDialog( builder: (context) => AssignTagModelsDialog(
products: products, products: products,
@ -142,9 +149,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
initialTags: state.initialTag, initialTags: state.initialTag,
title: dialogTitle, title: dialogTitle,
onUpdate: (tags, subspaces) { onUpdate: (tags, subspaces) {
if (onLoad != null) { onLoad?.call(tags, subspaces);
onLoad!(tags, subspaces);
}
}, },
), ),
); );