Made CommunityDialog reusable for edit and create features.

This commit is contained in:
Faris Armoush
2025-07-06 10:46:20 +03:00
parent 15b36fd052
commit 6dcc851d97
11 changed files with 161 additions and 111 deletions
@@ -39,6 +39,26 @@ class CommunityModel extends Equatable {
.toList();
}
CommunityModel copyWith({
String? uuid,
String? name,
DateTime? createdAt,
DateTime? updatedAt,
String? description,
String? externalId,
List<SpaceModel>? spaces,
}) {
return CommunityModel(
uuid: uuid ?? this.uuid,
name: name ?? this.name,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
description: description ?? this.description,
externalId: externalId ?? this.externalId,
spaces: spaces ?? this.spaces,
);
}
@override
List<Object?> get props => [uuid, name, spaces];
}
@@ -1,28 +1,23 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/widgets/community_dialog.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/bloc/communities_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/data/services/remote_create_community_service.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/domain/param/create_community_param.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/bloc/create_community_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_dialog_widget.dart';
import 'package:syncrow_web/services/api/http_service.dart';
class CreateCommunityDialog extends StatelessWidget {
final void Function(CommunityModel community) onCreateCommunity;
final String? initialName;
final Widget title;
const CreateCommunityDialog({
super.key,
required this.onCreateCommunity,
required this.title,
this.initialName,
});
const CreateCommunityDialog({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => CreateCommunityBloc(RemoteCreateCommunityService(HTTPService())),
child: BlocListener<CreateCommunityBloc, CreateCommunityState>(
create: (_) => CreateCommunityBloc(
RemoteCreateCommunityService(HTTPService()),
),
child: BlocConsumer<CreateCommunityBloc, CreateCommunityState>(
listener: (context, state) {
switch (state) {
case CreateCommunityLoading():
@@ -39,7 +34,12 @@ class CreateCommunityDialog extends StatelessWidget {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Community created successfully')),
);
onCreateCommunity.call(community);
context.read<CommunitiesBloc>().add(
InsertCommunity(community),
);
context.read<CommunitiesTreeSelectionBloc>().add(
SelectCommunityEvent(community: community),
);
break;
case CreateCommunityFailure():
Navigator.of(context).pop();
@@ -48,10 +48,16 @@ class CreateCommunityDialog extends StatelessWidget {
break;
}
},
child: CreateCommunityDialogWidget(
title: title,
initialName: initialName,
),
builder: (BuildContext context, CreateCommunityState state) {
return CommunityDialog(
title: const Text('Create Community'),
initialName: null,
onSubmit: (name) => context.read<CreateCommunityBloc>().add(
CreateCommunity(CreateCommunityParam(name: name)),
),
errorMessage: state is CreateCommunityFailure ? state.message : null,
);
},
),
);
}
@@ -1,144 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/domain/param/create_community_param.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/bloc/create_community_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/create_community/presentation/create_community_name_text_field.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CreateCommunityDialogWidget extends StatefulWidget {
final String? initialName;
final Widget title;
const CreateCommunityDialogWidget({
super.key,
required this.title,
this.initialName,
});
@override
State<CreateCommunityDialogWidget> createState() =>
_CreateCommunityDialogWidgetState();
}
class _CreateCommunityDialogWidgetState extends State<CreateCommunityDialogWidget> {
late final TextEditingController _nameController;
@override
void initState() {
_nameController = TextEditingController(text: widget.initialName ?? '');
super.initState();
}
@override
void dispose() {
_nameController.dispose();
super.dispose();
}
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
backgroundColor: ColorsManager.transparentColor,
child: Container(
width: MediaQuery.of(context).size.width * 0.3,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: ColorsManager.whiteColors,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: ColorsManager.blackColor.withValues(alpha: 0.25),
blurRadius: 20,
spreadRadius: 5,
offset: const Offset(0, 5),
),
],
),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: BlocBuilder<CreateCommunityBloc, CreateCommunityState>(
builder: (context, state) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DefaultTextStyle(
style: Theme.of(context).textTheme.headlineMedium!,
child: widget.title,
),
const SizedBox(height: 18),
CreateCommunityNameTextField(
nameController: _nameController,
),
if (state case CreateCommunityFailure(:final message))
Padding(
padding: const EdgeInsets.only(top: 18),
child: SelectableText(
'* $message',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.error,
),
),
),
const SizedBox(height: 24),
_buildActionButtons(context),
],
);
},
),
),
),
),
);
}
Widget _buildActionButtons(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: CancelButton(
label: 'Cancel',
onPressed: () => Navigator.of(context).pop(),
),
),
const SizedBox(width: 16),
_buildCreateCommunityButton(context),
],
);
}
Widget _buildCreateCommunityButton(BuildContext context) {
return Expanded(
child: DefaultButton(
onPressed: () {
if (_formKey.currentState?.validate() ?? false) {
_onSubmit(context);
}
},
borderRadius: 10,
foregroundColor: ColorsManager.whiteColors,
child: const Text('OK'),
),
);
}
void _onSubmit(BuildContext context) {
if (_formKey.currentState?.validate() ?? false) {
context.read<CreateCommunityBloc>().add(
CreateCommunity(
CreateCommunityParam(
name: _nameController.text.trim(),
),
),
);
}
}
}
@@ -1,6 +1,5 @@
import 'package:dio/dio.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/domain/params/update_community_param.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/domain/services/update_community_service.dart';
import 'package:syncrow_web/services/api/api_exception.dart';
import 'package:syncrow_web/services/api/http_service.dart';
@@ -13,7 +12,7 @@ class RemoteUpdateCommunityService implements UpdateCommunityService {
static const _defaultErrorMessage = 'Failed to update community';
@override
Future<CommunityModel> updateCommunity(UpdateCommunityParam param) async {
Future<CommunityModel> updateCommunity(CommunityModel param) async {
try {
final response = await _httpService.put(
path: 'endpoint',
@@ -1,10 +0,0 @@
import 'package:equatable/equatable.dart';
class UpdateCommunityParam extends Equatable {
const UpdateCommunityParam({required this.name});
final String name;
@override
List<Object> get props => [name];
}
@@ -1,6 +1,5 @@
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/domain/params/update_community_param.dart';
abstract class UpdateCommunityService {
Future<CommunityModel> updateCommunity(UpdateCommunityParam param);
Future<CommunityModel> updateCommunity(CommunityModel community);
}
@@ -1,7 +1,6 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/domain/params/update_community_param.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/domain/services/update_community_service.dart';
import 'package:syncrow_web/services/api/api_exception.dart';
@@ -24,7 +23,7 @@ class UpdateCommunityBloc extends Bloc<UpdateCommunityEvent, UpdateCommunityStat
emit(UpdateCommunityLoading());
try {
final updatedCommunity = await _updateCommunityService.updateCommunity(
event.param,
event.communityModel,
);
emit(UpdateCommunitySuccess(updatedCommunity));
} on APIException catch (e) {
@@ -8,10 +8,10 @@ sealed class UpdateCommunityEvent extends Equatable {
}
final class UpdateCommunity extends UpdateCommunityEvent {
const UpdateCommunity(this.param);
const UpdateCommunity(this.communityModel);
final UpdateCommunityParam param;
final CommunityModel communityModel ;
@override
List<Object> get props => [param];
List<Object> get props => [communityModel];
}
@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/space_management_v2/main_module/shared/widgets/community_dialog.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/community_model.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/data/services/remote_update_community_service.dart';
import 'package:syncrow_web/pages/space_management_v2/modules/update_community/presentation/bloc/update_community_bloc.dart';
import 'package:syncrow_web/services/api/http_service.dart';
class EditCommunityDialog extends StatelessWidget {
const EditCommunityDialog({required this.community, super.key});
final CommunityModel community;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) =>
UpdateCommunityBloc(RemoteUpdateCommunityService(HTTPService())),
child: BlocConsumer<UpdateCommunityBloc, UpdateCommunityState>(
listener: (context, state) {
switch (state) {
case UpdateCommunityLoading():
showDialog<void>(
context: context,
builder: (context) => const Center(
child: CircularProgressIndicator(),
),
);
break;
case UpdateCommunitySuccess(:final community):
Navigator.of(context).pop();
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${community.name} updated successfully'),
),
);
break;
case UpdateCommunityFailure():
Navigator.of(context).pop();
break;
default:
break;
}
},
builder: (context, state) => CommunityDialog(
title: const Text('Edit Community'),
initialName: community.name,
errorMessage: state is UpdateCommunityFailure ? state.message : null,
onSubmit: (name) => context.read<UpdateCommunityBloc>().add(
UpdateCommunity(community.copyWith(name: name)),
),
),
),
);
}
}