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,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/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/subspace_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';
@ -67,36 +68,102 @@ class CreateSpaceModelBloc
_space = event.spaceTemplate;
emit(CreateSpaceModelLoaded(_space!));
});
on<AddSubspacesToSpaceTemplate>((event, emit) {
final currentState = state;
if (currentState is CreateSpaceModelLoaded) {
final updatedSpace = currentState.space.copyWith(
subspaceModels: [
...(_space!.subspaceModels ?? []),
...event.subspaces,
],
);
final eventSubspaceIds =
event.subspaces.map((e) => e.internalId).toSet();
// 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));
} else {
emit(CreateSpaceModelError("Space template not initialized"));
}
});
on<AddTagsToSpaceTemplate>((event, emit) {
final currentState = state;
if (currentState is CreateSpaceModelLoaded) {
final updatedTags = currentState.space.copyWith(
tags: [
...(_space!.tags ?? []),
...event.tags,
],
);
emit(CreateSpaceModelLoaded(updatedTags));
final eventTagIds = event.tags.map((e) => e.internalId).toSet();
final updatedTags = currentState.space.tags
?.where((tag) => eventTagIds.contains(tag.internalId))
.map((tag) {
final matchingEventTag = event.tags.firstWhere(
(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 {
emit(CreateSpaceModelError("Space template not initialized"));
}
@ -106,7 +173,6 @@ class CreateSpaceModelBloc
final currentState = state;
if (currentState is CreateSpaceModelLoaded) {
if (event.name.trim().isEmpty) {
emit(CreateSpaceModelLoaded(
currentState.space,
errorMessage: "Model name cannot be empty",
@ -114,7 +180,7 @@ class CreateSpaceModelBloc
} else {
final updatedSpaceModel =
currentState.space.copyWith(modelName: event.name);
emit(CreateSpaceModelLoaded(updatedSpaceModel));
}
} else {

View File

@ -1,22 +1,28 @@
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
import 'package:uuid/uuid.dart';
class SubspaceTemplateModel {
final String? uuid;
String subspaceName;
final bool disabled;
List<TagModel>? tags;
String internalId;
SubspaceTemplateModel({
this.uuid,
required this.subspaceName,
required this.disabled,
this.tags,
});
String? internalId,
}) : internalId = internalId ?? const Uuid().v4();
factory SubspaceTemplateModel.fromJson(Map<String, dynamic> json) {
final String internalId = json['internalId'] ?? const Uuid().v4();
return SubspaceTemplateModel(
uuid: json['uuid'] ?? '',
subspaceName: json['subspaceName'] ?? '',
internalId: internalId,
disabled: json['disabled'] ?? false,
tags: (json['tags'] as List<dynamic>?)
?.map((item) => TagModel.fromJson(item))
@ -33,4 +39,20 @@ class SubspaceTemplateModel {
'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({
String? tag,
ProductModel? product,
String? location,
}) {
TagModel copyWith(
{String? tag,
ProductModel? product,
String? location,
String? internalId}) {
return TagModel(
tag: tag ?? this.tag,
product: product ?? this.product,
location: location ?? this.location,
internalId: internalId ?? this.internalId,
);
}
@ -58,4 +59,4 @@ extension TagModelExtensions on TagModel {
..tag = tag ?? ''
..productUuid = product?.uuid;
}
}
}

View File

@ -44,15 +44,15 @@ class CreateSpaceModelDialog extends StatelessWidget {
child: BlocProvider(
create: (_) {
final bloc = CreateSpaceModelBloc(_spaceModelApi);
if (spaceModel != null) {
bloc.add(UpdateSpaceTemplate(spaceModel!));
} else {
bloc.add(UpdateSpaceTemplate(SpaceTemplateModel(
modelName: '',
subspaceModels: const [],
)));
}
if (spaceModel != null) {
bloc.add(UpdateSpaceTemplate(spaceModel!));
} else {
bloc.add(UpdateSpaceTemplate(SpaceTemplateModel(
modelName: '',
subspaceModels: const [],
)));
}
spaceNameController.addListener(() {
bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text));
});
@ -72,7 +72,9 @@ class CreateSpaceModelDialog extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
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)
.textTheme
.headlineLarge
@ -127,16 +129,18 @@ class CreateSpaceModelDialog extends StatelessWidget {
allTags: allTags,
spaceNameController: spaceNameController,
onLoad: (tags, subspaces) {
if(subspaces!=null){
context
.read<CreateSpaceModelBloc>()
.add(AddSubspacesToSpaceTemplate(subspaces));
}
if(tags!=null){
if (context.read<CreateSpaceModelBloc>().state
is CreateSpaceModelLoaded) {
if (subspaces != null) {
context
.read<CreateSpaceModelBloc>()
.add(AddTagsToSpaceTemplate(tags));
.read<CreateSpaceModelBloc>()
.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_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/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/subspace_template_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,
children: [
// Combine tags from spaceModel and subspaces
..._groupTags([
...TagHelper.groupTags([
...?spaceModel?.tags,
...?spaceModel?.subspaceModels
?.expand((subspace) => subspace.tags ?? [])
@ -84,24 +85,32 @@ class TagChipDisplay extends StatelessWidget {
),
GestureDetector(
onTap: () async {
Navigator.of(context).pop();
// Use the Navigator's context for showDialog
final navigatorContext =
Navigator.of(context).overlay?.context;
await showDialog<bool>(
barrierDismissible: false,
context: context,
builder: (context) => AddDeviceTypeModelWidget(
isCreate: false,
products: products,
subspaces: subspaces,
allTags: allTags,
spaceName: spaceNameController.text,
spaceTagModels: spaceModel?.tags,
initialSelectedProducts:
_createInitialSelectedProducts(
spaceModel?.tags, spaceModel?.subspaceModels),
),
);
// Edit action
if (navigatorContext != null) {
await showDialog<bool>(
barrierDismissible: false,
context: navigatorContext,
builder: (context) => AssignTagModelsDialog(
products: products,
subspaces: subspaces,
allTags: allTags,
initialTags: TagHelper.generateInitialTags(
subspaces: subspaces,
spaceTagModels: spaceModel?.tags ?? []),
title: 'Edit Device',
addedProducts:
TagHelper.createInitialSelectedProducts(
spaceModel?.tags ?? [], subspaces),
spaceName: spaceModel?.modelName ?? '',
onUpdate: (tags, subspaces){
print("here");
onLoad?.call(tags, subspaces);}
),
);
}
},
child: Chip(
label: const Text(
@ -130,11 +139,7 @@ class TagChipDisplay extends StatelessWidget {
allTags: allTags,
spaceName: spaceNameController.text,
isCreate: true,
onLoad: (tags, subspaces) {
if (onLoad != null) {
onLoad!(tags, subspaces);
}
},
onLoad: (tags, subspaces) => onLoad?.call(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();
}
}