diff --git a/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart b/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart index 502ae4bb..3de9c192 100644 --- a/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart +++ b/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart @@ -11,7 +11,7 @@ class SpaceDetailsActionButtons extends StatelessWidget { }); final VoidCallback onCancel; - final VoidCallback onSave; + final VoidCallback? onSave; @override Widget build(BuildContext context) { diff --git a/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart b/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart index 1c435d8b..4230f7f4 100644 --- a/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart +++ b/lib/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart @@ -1,13 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart'; import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_details_action_buttons.dart'; -import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/subspace_chip.dart'; -import 'package:syncrow_web/pages/space_management_v2/modules/update_space/presentation/bloc/space_details_model_bloc/space_details_model_bloc.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:syncrow_web/utils/extension/build_context_x.dart'; +import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/sub_spaces_input.dart'; +import 'package:uuid/uuid.dart'; -class SpaceSubSpacesDialog extends StatelessWidget { +class SpaceSubSpacesDialog extends StatefulWidget { const SpaceSubSpacesDialog({ required this.subspaces, super.key, @@ -15,129 +12,73 @@ class SpaceSubSpacesDialog extends StatelessWidget { final List subspaces; + @override + State createState() => _SpaceSubSpacesDialogState(); +} + +class _SpaceSubSpacesDialogState extends State { + late List _subspaces; + + bool get _hasDuplicateNames => + _subspaces.map((subspace) => subspace.name.toLowerCase()).toSet().length != + _subspaces.length; + + @override + void initState() { + super.initState(); + _subspaces = List.from(widget.subspaces); + } + + void _handleSubspaceAdded(String name) { + setState(() { + _subspaces = [ + ..._subspaces, + Subspace( + name: name, + uuid: const Uuid().v4(), + productAllocations: const [], + ), + ]; + }); + } + + void _handleSubspaceDeleted(String uuid) => setState( + () => _subspaces = _subspaces.where((s) => s.uuid != uuid).toList(), + ); + + void _handleSave() => Navigator.of(context).pop(_subspaces); + @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Create Sub Spaces'), - content: TextFieldSubSpaceDialogWidget( - subSpaces: subspaces, + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SubSpacesInput( + subSpaces: _subspaces, + onSubspaceAdded: _handleSubspaceAdded, + onSubspaceDeleted: _handleSubspaceDeleted, + ), + AnimatedSwitcher( + duration: const Duration(milliseconds: 100), + child: Visibility( + key: ValueKey(_hasDuplicateNames), + visible: _hasDuplicateNames, + child: const Text( + 'Error: Duplicate subspace names are not allowed.', + style: TextStyle(color: Colors.red), + ), + ), + ), + ], ), actions: [ SpaceDetailsActionButtons( - onSave: () {}, + onSave: _hasDuplicateNames ? null : _handleSave, onCancel: Navigator.of(context).pop, ) ], ); } } - -class TextFieldSubSpaceDialogWidget extends StatefulWidget { - const TextFieldSubSpaceDialogWidget({ - super.key, - required this.subSpaces, - }); - - final List subSpaces; - - @override - State createState() => _TextFieldSubSpaceDialogWidgetState(); -} - -class _TextFieldSubSpaceDialogWidgetState extends State { - - late final TextEditingController _subspaceNameController; - - @override - void initState() { - super.initState(); - _subspaceNameController = TextEditingController(); - } - - @override - void dispose() { - _subspaceNameController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Container( - width: context.screenWidth * 0.35, - padding: const EdgeInsets.symmetric( - vertical: 10, - horizontal: 16, - ), - decoration: BoxDecoration( - color: ColorsManager.boxColor, - borderRadius: BorderRadius.circular(10), - ), - child: Wrap( - spacing: 8, - runSpacing: 8, - alignment: WrapAlignment.start, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - ...widget.subSpaces.asMap().entries.map( - (entry) { - final index = entry.key; - final subSpace = entry.value; - - final lowerName = subSpace.name.toLowerCase(); - - final duplicateIndices = widget.subSpaces - .asMap() - .entries - .where((e) => e.value.name.toLowerCase() == lowerName) - .map((e) => e.key) - .toList(); - final isDuplicate = duplicateIndices.length > 1 && - duplicateIndices.indexOf(index) != 0; - return SubspaceChip( - subSpace: subSpace, - isDuplicate: isDuplicate, - onDeleted: () => context.read().add( - UpdateSpaceDetailsSubspaces( - widget.subSpaces.where((e) => e.uuid != subSpace.uuid).toList(), - ), - ), - ); - }, - ), - SizedBox( - width: 200, - child: TextField( - controller: _subspaceNameController, - decoration: InputDecoration( - border: InputBorder.none, - hintText: widget.subSpaces.isEmpty ? 'Please enter the name' : null, - hintStyle: context.textTheme.bodySmall?.copyWith( - color: ColorsManager.lightGrayColor, - ), - ), - onSubmitted: (value) { - final trimmedValue = value.trim(); - if (trimmedValue.isNotEmpty) { - context.read().add( - UpdateSpaceDetailsSubspaces( - [ - ...widget.subSpaces, - Subspace( - name: trimmedValue, - uuid: '', - productAllocations: const [], - ), - ], - ), - ); - _subspaceNameController.clear(); - } - }, - style: context.textTheme.bodyMedium, - ), - ), - ], - ), - ); - } -} diff --git a/lib/pages/space_management_v2/modules/space_details/presentation/widgets/sub_spaces_input.dart b/lib/pages/space_management_v2/modules/space_details/presentation/widgets/sub_spaces_input.dart new file mode 100644 index 00000000..1e1edb89 --- /dev/null +++ b/lib/pages/space_management_v2/modules/space_details/presentation/widgets/sub_spaces_input.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart'; +import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/subspace_chip.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class SubSpacesInput extends StatefulWidget { + const SubSpacesInput({ + super.key, + required this.subSpaces, + required this.onSubspaceAdded, + required this.onSubspaceDeleted, + }); + + final List subSpaces; + final void Function(String name) onSubspaceAdded; + final void Function(String uuid) onSubspaceDeleted; + + @override + State createState() => _SubSpacesInputState(); +} + +class _SubSpacesInputState extends State { + late final TextEditingController _subspaceNameController; + + @override + void initState() { + super.initState(); + _subspaceNameController = TextEditingController(); + } + + @override + void dispose() { + _subspaceNameController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: context.screenWidth * 0.35, + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 16, + ), + decoration: BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.circular(10), + ), + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + ...widget.subSpaces.asMap().entries.map( + (entry) { + final index = entry.key; + final subSpace = entry.value; + + final lowerName = subSpace.name.toLowerCase(); + + final duplicateIndices = widget.subSpaces + .asMap() + .entries + .where((e) => e.value.name.toLowerCase() == lowerName) + .map((e) => e.key) + .toList(); + final isDuplicate = duplicateIndices.length > 1 && + duplicateIndices.indexOf(index) != 0; + return SubspaceChip( + subSpace: subSpace, + isDuplicate: isDuplicate, + onDeleted: () => widget.onSubspaceDeleted(subSpace.uuid), + ); + }, + ), + SizedBox( + width: 200, + child: TextField( + controller: _subspaceNameController, + decoration: InputDecoration( + border: InputBorder.none, + hintText: widget.subSpaces.isEmpty ? 'Please enter the name' : null, + hintStyle: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGrayColor, + ), + ), + onSubmitted: (value) { + final trimmedValue = value.trim(); + if (trimmedValue.isNotEmpty) { + widget.onSubspaceAdded(trimmedValue); + _subspaceNameController.clear(); + } + }, + style: context.textTheme.bodyMedium, + ), + ), + ], + ), + ); + } +}