updated duplication ui

This commit is contained in:
hannathkadher
2025-01-15 11:29:19 +04:00
parent 5975adb5e2
commit a7256c8d5d
3 changed files with 116 additions and 61 deletions

View File

@ -6,19 +6,23 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_
import 'package:syncrow_web/utils/constants/action_enum.dart'; import 'package:syncrow_web/utils/constants/action_enum.dart';
class SubSpaceModelBloc extends Bloc<SubSpaceModelEvent, SubSpaceModelState> { class SubSpaceModelBloc extends Bloc<SubSpaceModelEvent, SubSpaceModelState> {
SubSpaceModelBloc() : super(SubSpaceModelState([], [], '')) { SubSpaceModelBloc() : super(SubSpaceModelState([], [], '', {})) {
// Handle AddSubSpaceModel Event // Handle AddSubSpaceModel Event
on<AddSubSpaceModel>((event, emit) { on<AddSubSpaceModel>((event, emit) {
// Check for duplicate names (case-insensitive)
final existingNames = final existingNames =
state.subSpaces.map((e) => e.subspaceName.toLowerCase()).toSet(); state.subSpaces.map((e) => e.subspaceName.toLowerCase()).toSet();
if (existingNames.contains(event.subSpace.subspaceName.toLowerCase())) { if (existingNames.contains(event.subSpace.subspaceName.toLowerCase())) {
// Emit state with an error message if duplicate name exists final updatedDuplicates = Set<String>.from(state.duplicates)
..add(event.subSpace.subspaceName.toLowerCase());
final updatedSubSpaces =
List<SubspaceTemplateModel>.from(state.subSpaces)
..add(event.subSpace);
emit(SubSpaceModelState( emit(SubSpaceModelState(
state.subSpaces, updatedSubSpaces,
state.updatedSubSpaceModels, state.updatedSubSpaceModels,
'Subspace name already exists.', '*Duplicated sub-space name',
updatedDuplicates,
)); ));
} else { } else {
// Add subspace if no duplicate exists // Add subspace if no duplicate exists
@ -29,7 +33,9 @@ class SubSpaceModelBloc extends Bloc<SubSpaceModelEvent, SubSpaceModelState> {
emit(SubSpaceModelState( emit(SubSpaceModelState(
updatedSubSpaces, updatedSubSpaces,
state.updatedSubSpaceModels, state.updatedSubSpaceModels,
'', // Clear error message '',
state.duplicates,
// Clear error message
)); ));
} }
}); });
@ -42,6 +48,16 @@ class SubSpaceModelBloc extends Bloc<SubSpaceModelEvent, SubSpaceModelState> {
final updatedSubspaceModels = List<UpdateSubspaceTemplateModel>.from( final updatedSubspaceModels = List<UpdateSubspaceTemplateModel>.from(
state.updatedSubSpaceModels, state.updatedSubSpaceModels,
); );
final nameOccurrences = <String, int>{};
for (final subSpace in updatedSubSpaces) {
final lowerName = subSpace.subspaceName.toLowerCase();
nameOccurrences[lowerName] = (nameOccurrences[lowerName] ?? 0) + 1;
}
final updatedDuplicates = nameOccurrences.entries
.where((entry) => entry.value > 1)
.map((entry) => entry.key)
.toSet();
if (event.subSpace.uuid?.isNotEmpty ?? false) { if (event.subSpace.uuid?.isNotEmpty ?? false) {
updatedSubspaceModels.add(UpdateSubspaceTemplateModel( updatedSubspaceModels.add(UpdateSubspaceTemplateModel(
@ -53,7 +69,9 @@ class SubSpaceModelBloc extends Bloc<SubSpaceModelEvent, SubSpaceModelState> {
emit(SubSpaceModelState( emit(SubSpaceModelState(
updatedSubSpaces, updatedSubSpaces,
updatedSubspaceModels, updatedSubspaceModels,
'', // Clear error message '',
updatedDuplicates,
// Clear error message
)); ));
}); });
@ -78,7 +96,9 @@ class SubSpaceModelBloc extends Bloc<SubSpaceModelEvent, SubSpaceModelState> {
emit(SubSpaceModelState( emit(SubSpaceModelState(
updatedSubSpaces, updatedSubSpaces,
updatedSubspaceModels, updatedSubspaceModels,
'', // Clear error message '',
state.duplicates,
// Clear error message
)); ));
}); });
} }

View File

@ -5,22 +5,26 @@ class SubSpaceModelState {
final List<SubspaceTemplateModel> subSpaces; final List<SubspaceTemplateModel> subSpaces;
final List<UpdateSubspaceTemplateModel> updatedSubSpaceModels; final List<UpdateSubspaceTemplateModel> updatedSubSpaceModels;
final String errorMessage; final String errorMessage;
final Set<String> duplicates;
SubSpaceModelState( SubSpaceModelState(
this.subSpaces, this.subSpaces,
this.updatedSubSpaceModels, this.updatedSubSpaceModels,
this.errorMessage, this.errorMessage,
this.duplicates,
); );
SubSpaceModelState copyWith({ SubSpaceModelState copyWith({
List<SubspaceTemplateModel>? subSpaces, List<SubspaceTemplateModel>? subSpaces,
List<UpdateSubspaceTemplateModel>? updatedSubSpaceModels, List<UpdateSubspaceTemplateModel>? updatedSubSpaceModels,
String? errorMessage, String? errorMessage,
Set<String>? duplicates,
}) { }) {
return SubSpaceModelState( return SubSpaceModelState(
subSpaces ?? this.subSpaces, subSpaces ?? this.subSpaces,
updatedSubSpaceModels ?? this.updatedSubSpaceModels, updatedSubSpaceModels ?? this.updatedSubSpaceModels,
errorMessage ?? this.errorMessage, errorMessage ?? this.errorMessage,
duplicates ?? this.duplicates,
); );
} }
} }

View File

@ -46,7 +46,7 @@ class CreateSubSpaceModelDialog extends StatelessWidget {
return Container( return Container(
color: ColorsManager.whiteColors, color: ColorsManager.whiteColors,
child: SizedBox( child: SizedBox(
width: screenWidth * 0.35, width: screenWidth * 0.3,
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
@ -73,41 +73,64 @@ class CreateSubSpaceModelDialog extends StatelessWidget {
spacing: 8.0, spacing: 8.0,
runSpacing: 8.0, runSpacing: 8.0,
children: [ children: [
...state.subSpaces.map( ...state.subSpaces.asMap().entries.map(
(subSpace) => Chip( (entry) {
label: Text( final index = entry.key;
subSpace.subspaceName, final subSpace = entry.value;
style: const TextStyle(
color: ColorsManager.spaceColor), final lowerName =
), subSpace.subspaceName.toLowerCase();
backgroundColor: ColorsManager.whiteColors,
shape: RoundedRectangleBorder( final duplicateIndices = state.subSpaces
borderRadius: BorderRadius.circular(8), .asMap()
side: const BorderSide( .entries
color: ColorsManager.transparentColor, .where((e) =>
width: 0, e.value.subspaceName.toLowerCase() ==
), lowerName)
), .map((e) => e.key)
deleteIcon: Container( .toList();
width: 24, final isDuplicate =
height: 24, duplicateIndices.length > 1 &&
decoration: BoxDecoration( duplicateIndices.indexOf(index) != 0;
shape: BoxShape.circle,
border: Border.all( return Chip(
color: ColorsManager.lightGrayColor, label: Text(
width: 1.5, subSpace.subspaceName,
style: const TextStyle(
color: ColorsManager.spaceColor,
), ),
), ),
child: const Icon( backgroundColor: ColorsManager.whiteColors,
Icons.close, shape: RoundedRectangleBorder(
size: 16, borderRadius: BorderRadius.circular(10),
color: ColorsManager.lightGrayColor, side: BorderSide(
color: isDuplicate
? ColorsManager.red
: ColorsManager.transparentColor,
width: 0,
),
), ),
), deleteIcon: Container(
onDeleted: () => context width: 24,
.read<SubSpaceModelBloc>() height: 24,
.add(RemoveSubSpaceModel(subSpace)), decoration: BoxDecoration(
), shape: BoxShape.circle,
border: Border.all(
color: ColorsManager.lightGrayColor,
width: 1.5,
),
),
child: const Icon(
Icons.close,
size: 16,
color: ColorsManager.lightGrayColor,
),
),
onDeleted: () => context
.read<SubSpaceModelBloc>()
.add(RemoveSubSpaceModel(subSpace)),
);
},
), ),
SizedBox( SizedBox(
width: 200, width: 200,
@ -135,20 +158,20 @@ class CreateSubSpaceModelDialog extends StatelessWidget {
color: ColorsManager.blackColor), color: ColorsManager.blackColor),
), ),
), ),
if (state.errorMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
state.errorMessage,
style: const TextStyle(
color: ColorsManager.warningRed,
fontSize: 12,
),
),
),
], ],
), ),
), ),
if (state.errorMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: Text(
state.errorMessage,
style: const TextStyle(
color: ColorsManager.red,
fontSize: 12,
),
),
),
const SizedBox(height: 16), const SizedBox(height: 16),
Row( Row(
children: [ children: [
@ -163,17 +186,25 @@ class CreateSubSpaceModelDialog extends StatelessWidget {
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: DefaultButton( child: DefaultButton(
onPressed: () async { onPressed: (state.subSpaces.isEmpty ||
final subSpaces = context state.errorMessage.isNotEmpty)
.read<SubSpaceModelBloc>() ? null
.state : () async {
.subSpaces; final subSpaces = context
Navigator.of(context).pop(); .read<SubSpaceModelBloc>()
onUpdate!(subSpaces); .state
}, .subSpaces;
Navigator.of(context).pop();
if (onUpdate != null) {
onUpdate!(subSpaces);
}
},
backgroundColor: ColorsManager.secondaryColor, backgroundColor: ColorsManager.secondaryColor,
borderRadius: 10, borderRadius: 10,
foregroundColor: ColorsManager.whiteColors, foregroundColor: state.subSpaces.isEmpty ||
state.errorMessage.isNotEmpty
? ColorsManager.whiteColorsWithOpacity
: ColorsManager.whiteColors,
child: const Text('OK'), child: const Text('OK'),
), ),
), ),