mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-08-26 07:29:41 +00:00
Compare commits
8 Commits
d65f9ceea9
...
f03c28f7fd
Author | SHA1 | Date | |
---|---|---|---|
f03c28f7fd | |||
6ec972a520 | |||
62f67f5a5f | |||
8e303af0d7 | |||
4ef4858cee | |||
9a203b2fd9 | |||
39c5fd1bca | |||
308eb65d46 |
@ -40,4 +40,24 @@ abstract final class SpacesRecursiveHelper {
|
|||||||
final nonNullSpaces = updatedSpaces.whereType<SpaceModel>().toList();
|
final nonNullSpaces = updatedSpaces.whereType<SpaceModel>().toList();
|
||||||
return nonNullSpaces;
|
return nonNullSpaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<SpaceModel> recusrivelyInsert(
|
||||||
|
List<SpaceModel> spaces,
|
||||||
|
SpaceModel newSpace,
|
||||||
|
String parentUuid,
|
||||||
|
) {
|
||||||
|
return spaces.map((space) {
|
||||||
|
if (space.uuid == parentUuid) {
|
||||||
|
return space.copyWith(
|
||||||
|
children: [...space.children, newSpace],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (space.children.isNotEmpty) {
|
||||||
|
return space.copyWith(
|
||||||
|
children: recusrivelyInsert(space.children, newSpace, parentUuid),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return space;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/main_module/helpers/spaces_recursive_helper.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_connection_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_reorder_data_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/models/space_reorder_data_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/painters/spaces_connections_arrow_painter.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/painters/spaces_connections_arrow_painter.dart';
|
||||||
@ -268,7 +269,7 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
Positioned(
|
Positioned(
|
||||||
left: createButtonX,
|
left: createButtonX,
|
||||||
top: createButtonY,
|
top: createButtonY,
|
||||||
child: CreateSpaceButton(communityUuid: widget.community.uuid),
|
child: CreateSpaceButton(community: widget.community),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -327,6 +328,19 @@ class _CommunityStructureCanvasState extends State<CommunityStructureCanvas>
|
|||||||
onTap: () => SpaceDetailsDialogHelper.showCreate(
|
onTap: () => SpaceDetailsDialogHelper.showCreate(
|
||||||
context,
|
context,
|
||||||
communityUuid: widget.community.uuid,
|
communityUuid: widget.community.uuid,
|
||||||
|
parentUuid: space.uuid,
|
||||||
|
onSuccess: (updatedSpaceModel) {
|
||||||
|
final updatedSpaces = SpacesRecursiveHelper.recusrivelyInsert(
|
||||||
|
spaces,
|
||||||
|
updatedSpaceModel,
|
||||||
|
space.uuid,
|
||||||
|
);
|
||||||
|
context.read<CommunitiesBloc>().add(
|
||||||
|
CommunitiesUpdateCommunity(
|
||||||
|
widget.community.copyWith(spaces: updatedSpaces),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/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/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/helpers/space_details_dialog_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class CreateSpaceButton extends StatefulWidget {
|
class CreateSpaceButton extends StatefulWidget {
|
||||||
const CreateSpaceButton({
|
const CreateSpaceButton({
|
||||||
required this.communityUuid,
|
required this.community,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String communityUuid;
|
final CommunityModel community;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CreateSpaceButton> createState() => _CreateSpaceButtonState();
|
State<CreateSpaceButton> createState() => _CreateSpaceButtonState();
|
||||||
@ -25,7 +29,21 @@ class _CreateSpaceButtonState extends State<CreateSpaceButton> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => SpaceDetailsDialogHelper.showCreate(
|
onTap: () => SpaceDetailsDialogHelper.showCreate(
|
||||||
context,
|
context,
|
||||||
communityUuid: widget.communityUuid,
|
communityUuid: widget.community.uuid,
|
||||||
|
onSuccess: (updatedSpaceModel) {
|
||||||
|
final newCommunity = widget.community.copyWith(
|
||||||
|
spaces: [...widget.community.spaces, updatedSpaceModel],
|
||||||
|
);
|
||||||
|
context.read<CommunitiesBloc>().add(
|
||||||
|
CommunitiesUpdateCommunity(newCommunity),
|
||||||
|
);
|
||||||
|
context.read<CommunitiesTreeSelectionBloc>().add(
|
||||||
|
SelectSpaceEvent(
|
||||||
|
space: updatedSpaceModel,
|
||||||
|
community: newCommunity,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
onEnter: (_) => setState(() => _isHovered = true),
|
onEnter: (_) => setState(() => _isHovered = true),
|
||||||
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/commun
|
|||||||
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/create_space_button.dart';
|
import 'package:syncrow_web/pages/space_management_v2/main_module/widgets/create_space_button.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/communities/domain/models/community_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.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/communities/presentation/communities_tree_selection_bloc/communities_tree_selection_bloc.dart';
|
||||||
|
|
||||||
class SpaceManagementCommunityStructure extends StatelessWidget {
|
class SpaceManagementCommunityStructure extends StatelessWidget {
|
||||||
@ -12,19 +13,35 @@ class SpaceManagementCommunityStructure extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final selectionBloc = context.watch<CommunitiesTreeSelectionBloc>().state;
|
return BlocBuilder<CommunitiesTreeSelectionBloc, CommunitiesTreeSelectionState>(
|
||||||
final selectedCommunity = selectionBloc.selectedCommunity;
|
builder: (context, state) {
|
||||||
final selectedSpace = selectionBloc.selectedSpace;
|
final selectedCommunity = state.selectedCommunity;
|
||||||
return Column(
|
final selectedSpace = state.selectedSpace;
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
if (selectedCommunity == null) {
|
||||||
const CommunityStructureHeader(),
|
return const SizedBox.shrink();
|
||||||
Visibility(
|
}
|
||||||
visible: selectedCommunity!.spaces.isNotEmpty,
|
|
||||||
replacement: _buildEmptyWidget(selectedCommunity),
|
return Column(
|
||||||
child: _buildCanvas(selectedCommunity, selectedSpace),
|
mainAxisSize: MainAxisSize.min,
|
||||||
),
|
children: [
|
||||||
],
|
const CommunityStructureHeader(),
|
||||||
|
BlocBuilder<CommunitiesBloc, CommunitiesState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final community = state.communities.firstWhere(
|
||||||
|
(element) => element.uuid == selectedCommunity.uuid,
|
||||||
|
orElse: () => selectedCommunity,
|
||||||
|
);
|
||||||
|
return Visibility(
|
||||||
|
visible: community.spaces.isNotEmpty,
|
||||||
|
replacement: _buildEmptyWidget(community),
|
||||||
|
child: _buildCanvas(community, selectedSpace),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +64,7 @@ class SpaceManagementCommunityStructure extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
spacer,
|
spacer,
|
||||||
Expanded(
|
Expanded(child: CreateSpaceButton(community: selectedCommunity)),
|
||||||
child: CreateSpaceButton(
|
|
||||||
communityUuid: selectedCommunity.uuid,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
spacer,
|
spacer,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/domain/params/create_space_param.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/domain/services/create_space_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
import 'package:syncrow_web/services/api/http_service.dart';
|
||||||
|
|
||||||
|
final class RemoteCreateSpaceService implements CreateSpaceService {
|
||||||
|
const RemoteCreateSpaceService(this._httpService);
|
||||||
|
|
||||||
|
final HTTPService _httpService;
|
||||||
|
|
||||||
|
static const _defaultErrorMessage = 'Failed to create space';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<SpaceModel> createSpace(CreateSpaceParam param) async {
|
||||||
|
try {
|
||||||
|
final path = await _makeUrl(param);
|
||||||
|
final response = await _httpService.post(
|
||||||
|
path: path,
|
||||||
|
body: param.toJson(),
|
||||||
|
expectedResponseModel: (data) {
|
||||||
|
final response = data as Map<String, dynamic>;
|
||||||
|
final isSuccess = response['success'] as bool;
|
||||||
|
if (!isSuccess) {
|
||||||
|
throw APIException(response['error'] as String);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SpaceModel.fromJson(response['data'] as Map<String, dynamic>);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
|
final errorMessage = error?['error'] as String? ?? '';
|
||||||
|
final formattedErrorMessage = [
|
||||||
|
_defaultErrorMessage,
|
||||||
|
errorMessage,
|
||||||
|
].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
|
} catch (e) {
|
||||||
|
final formattedErrorMessage = [_defaultErrorMessage, '$e'].join(': ');
|
||||||
|
throw APIException(formattedErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _makeUrl(CreateSpaceParam param) async {
|
||||||
|
final projectUuid = await ProjectManager.getProjectUUID();
|
||||||
|
if (projectUuid == null || projectUuid.isEmpty) {
|
||||||
|
throw APIException('Project UUID is not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
final communityUuid = param.communityUuid;
|
||||||
|
if (communityUuid.isEmpty) {
|
||||||
|
throw APIException('Community UUID is not set');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '/projects/$projectUuid/communities/$communityUuid/spaces';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/space_details_model.dart';
|
||||||
|
|
||||||
|
class CreateSpaceParam {
|
||||||
|
final String communityUuid;
|
||||||
|
final SpaceDetailsModel space;
|
||||||
|
final String? parentUuid;
|
||||||
|
|
||||||
|
const CreateSpaceParam({
|
||||||
|
required this.communityUuid,
|
||||||
|
required this.space,
|
||||||
|
required this.parentUuid,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'spaceModelUuid': parentUuid,
|
||||||
|
...space.toJson(),
|
||||||
|
'x': 0,
|
||||||
|
'y': 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/domain/params/create_space_param.dart';
|
||||||
|
|
||||||
|
abstract interface class CreateSpaceService {
|
||||||
|
Future<SpaceModel> createSpace(CreateSpaceParam param);
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/domain/params/create_space_param.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/domain/services/create_space_service.dart';
|
||||||
|
import 'package:syncrow_web/services/api/api_exception.dart';
|
||||||
|
|
||||||
|
part 'create_space_event.dart';
|
||||||
|
part 'create_space_state.dart';
|
||||||
|
|
||||||
|
class CreateSpaceBloc extends Bloc<CreateSpaceEvent, CreateSpaceState> {
|
||||||
|
CreateSpaceBloc(
|
||||||
|
this._createSpaceService,
|
||||||
|
) : super(const CreateSpaceInitial()) {
|
||||||
|
on<CreateSpace>(_onCreateSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
final CreateSpaceService _createSpaceService;
|
||||||
|
|
||||||
|
Future<void> _onCreateSpace(
|
||||||
|
CreateSpace event,
|
||||||
|
Emitter<CreateSpaceState> emit,
|
||||||
|
) async {
|
||||||
|
emit(const CreateSpaceLoading());
|
||||||
|
try {
|
||||||
|
final result = await _createSpaceService.createSpace(event.param);
|
||||||
|
emit(CreateSpaceSuccess(result));
|
||||||
|
} on APIException catch (e) {
|
||||||
|
emit(CreateSpaceFailure(e.message));
|
||||||
|
} catch (e) {
|
||||||
|
emit(CreateSpaceFailure(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
part of 'create_space_bloc.dart';
|
||||||
|
|
||||||
|
sealed class CreateSpaceEvent extends Equatable {
|
||||||
|
const CreateSpaceEvent();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class CreateSpace extends CreateSpaceEvent {
|
||||||
|
const CreateSpace(this.param);
|
||||||
|
|
||||||
|
final CreateSpaceParam param;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [param];
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
part of 'create_space_bloc.dart';
|
||||||
|
|
||||||
|
sealed class CreateSpaceState extends Equatable {
|
||||||
|
const CreateSpaceState();
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class CreateSpaceInitial extends CreateSpaceState {
|
||||||
|
const CreateSpaceInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
final class CreateSpaceLoading extends CreateSpaceState {
|
||||||
|
const CreateSpaceLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
final class CreateSpaceSuccess extends CreateSpaceState {
|
||||||
|
const CreateSpaceSuccess(this.space);
|
||||||
|
|
||||||
|
final SpaceModel space;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [space];
|
||||||
|
}
|
||||||
|
|
||||||
|
final class CreateSpaceFailure extends CreateSpaceState {
|
||||||
|
const CreateSpaceFailure(this.errorMessage);
|
||||||
|
|
||||||
|
final String errorMessage;
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
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/domain/models/space_details_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/subspace.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/params/load_space_details_param.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/services/space_details_service.dart';
|
||||||
|
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
class ProductAllocation extends Equatable {
|
||||||
|
final String uuid;
|
||||||
|
final Product product;
|
||||||
|
final Tag tag;
|
||||||
|
|
||||||
|
const ProductAllocation({
|
||||||
|
required this.uuid,
|
||||||
|
required this.product,
|
||||||
|
required this.tag,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ProductAllocation.fromJson(Map<String, dynamic> json) {
|
||||||
|
return ProductAllocation(
|
||||||
|
uuid: json['uuid'] as String? ?? const Uuid().v4(),
|
||||||
|
product: Product.fromJson(json['product'] as Map<String, dynamic>),
|
||||||
|
tag: Tag.fromJson(json['tag'] as Map<String, dynamic>),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductAllocation copyWith({
|
||||||
|
String? uuid,
|
||||||
|
Product? product,
|
||||||
|
Tag? tag,
|
||||||
|
}) {
|
||||||
|
return ProductAllocation(
|
||||||
|
uuid: uuid ?? this.uuid,
|
||||||
|
product: product ?? this.product,
|
||||||
|
tag: tag ?? this.tag,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final isNewTag = tag.uuid.isEmpty;
|
||||||
|
return <String, dynamic>{
|
||||||
|
if (isNewTag) 'tagName': tag.name else 'tagUuid': tag.uuid,
|
||||||
|
'productUuid': product.uuid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [uuid, product, tag];
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/product_allocation.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/subspace.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class SpaceDetailsModel extends Equatable {
|
class SpaceDetailsModel extends Equatable {
|
||||||
final String uuid;
|
final String uuid;
|
||||||
@ -26,6 +25,7 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
productAllocations: [],
|
productAllocations: [],
|
||||||
subspaces: [],
|
subspaces: [],
|
||||||
);
|
);
|
||||||
|
|
||||||
factory SpaceDetailsModel.fromJson(Map<String, dynamic> json) {
|
factory SpaceDetailsModel.fromJson(Map<String, dynamic> json) {
|
||||||
return SpaceDetailsModel(
|
return SpaceDetailsModel(
|
||||||
uuid: json['uuid'] as String,
|
uuid: json['uuid'] as String,
|
||||||
@ -56,78 +56,21 @@ class SpaceDetailsModel extends Equatable {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Map<String, dynamic> toJson() {
|
||||||
List<Object?> get props => [uuid, spaceName, icon, productAllocations, subspaces];
|
return {
|
||||||
}
|
'spaceName': spaceName,
|
||||||
|
'icon': icon,
|
||||||
class ProductAllocation extends Equatable {
|
'subspaces': subspaces.map((e) => e.toJson()).toList(),
|
||||||
final String uuid;
|
'productAllocations': productAllocations.map((e) => e.toJson()).toList(),
|
||||||
final Product product;
|
};
|
||||||
final Tag tag;
|
|
||||||
|
|
||||||
const ProductAllocation({
|
|
||||||
required this.uuid,
|
|
||||||
required this.product,
|
|
||||||
required this.tag,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory ProductAllocation.fromJson(Map<String, dynamic> json) {
|
|
||||||
return ProductAllocation(
|
|
||||||
uuid: json['uuid'] as String? ?? const Uuid().v4(),
|
|
||||||
product: Product.fromJson(json['product'] as Map<String, dynamic>),
|
|
||||||
tag: Tag.fromJson(json['tag'] as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProductAllocation copyWith({
|
|
||||||
String? uuid,
|
|
||||||
Product? product,
|
|
||||||
Tag? tag,
|
|
||||||
}) {
|
|
||||||
return ProductAllocation(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
product: product ?? this.product,
|
|
||||||
tag: tag ?? this.tag,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [uuid, product, tag];
|
List<Object?> get props => [
|
||||||
}
|
uuid,
|
||||||
|
spaceName,
|
||||||
class Subspace extends Equatable {
|
icon,
|
||||||
final String uuid;
|
productAllocations,
|
||||||
final String name;
|
subspaces,
|
||||||
final List<ProductAllocation> productAllocations;
|
];
|
||||||
|
|
||||||
const Subspace({
|
|
||||||
required this.uuid,
|
|
||||||
required this.name,
|
|
||||||
required this.productAllocations,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory Subspace.fromJson(Map<String, dynamic> json) {
|
|
||||||
return Subspace(
|
|
||||||
uuid: json['uuid'] as String,
|
|
||||||
name: json['subspaceName'] as String,
|
|
||||||
productAllocations: (json['productAllocations'] as List)
|
|
||||||
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Subspace copyWith({
|
|
||||||
String? uuid,
|
|
||||||
String? name,
|
|
||||||
List<ProductAllocation>? productAllocations,
|
|
||||||
}) {
|
|
||||||
return Subspace(
|
|
||||||
uuid: uuid ?? this.uuid,
|
|
||||||
name: name ?? this.name,
|
|
||||||
productAllocations: productAllocations ?? this.productAllocations,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [uuid, name, productAllocations];
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/product_allocation.dart';
|
||||||
|
|
||||||
|
class Subspace extends Equatable {
|
||||||
|
final String uuid;
|
||||||
|
final String name;
|
||||||
|
final List<ProductAllocation> productAllocations;
|
||||||
|
|
||||||
|
const Subspace({
|
||||||
|
required this.uuid,
|
||||||
|
required this.name,
|
||||||
|
required this.productAllocations,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Subspace.fromJson(Map<String, dynamic> json) {
|
||||||
|
return Subspace(
|
||||||
|
uuid: json['uuid'] as String,
|
||||||
|
name: json['subspaceName'] as String,
|
||||||
|
productAllocations: (json['productAllocations'] as List)
|
||||||
|
.map((e) => ProductAllocation.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final isNewSubspace = uuid.endsWith('-NewTag');
|
||||||
|
return <String, dynamic>{
|
||||||
|
if (!isNewSubspace) 'uuid': uuid,
|
||||||
|
'subspaceName': name,
|
||||||
|
'productAllocations': productAllocations.map((e) => e.toJson()).toList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Subspace copyWith({
|
||||||
|
String? uuid,
|
||||||
|
String? name,
|
||||||
|
List<ProductAllocation>? productAllocations,
|
||||||
|
}) {
|
||||||
|
return Subspace(
|
||||||
|
uuid: uuid ?? this.uuid,
|
||||||
|
name: name ?? this.name,
|
||||||
|
productAllocations: productAllocations ?? this.productAllocations,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [uuid, name, productAllocations];
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/communities/domain/models/space_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/data/services/remote_create_space_service.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/domain/params/create_space_param.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/create_space/presentation/bloc/create_space_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/data/services/remote_space_details_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/data/services/remote_space_details_service.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/domain/models/space_details_model.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/bloc/space_details_bloc.dart';
|
||||||
@ -14,6 +17,8 @@ abstract final class SpaceDetailsDialogHelper {
|
|||||||
static void showCreate(
|
static void showCreate(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
required String communityUuid,
|
required String communityUuid,
|
||||||
|
required void Function(SpaceModel updatedSpaceModel)? onSuccess,
|
||||||
|
String? parentUuid,
|
||||||
}) {
|
}) {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
@ -24,14 +29,41 @@ abstract final class SpaceDetailsDialogHelper {
|
|||||||
RemoteSpaceDetailsService(httpService: HTTPService()),
|
RemoteSpaceDetailsService(httpService: HTTPService()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
BlocProvider(
|
||||||
|
create: (context) => CreateSpaceBloc(
|
||||||
|
RemoteCreateSpaceService(HTTPService()),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => SpaceDetailsDialog(
|
builder: (context) => BlocListener<CreateSpaceBloc, CreateSpaceState>(
|
||||||
context: context,
|
listener: (context, state) => switch (state) {
|
||||||
title: const SelectableText('Create Space'),
|
CreateSpaceInitial() => null,
|
||||||
spaceModel: SpaceModel.empty(),
|
CreateSpaceLoading() => _onLoading(context),
|
||||||
onSave: (space) {},
|
CreateSpaceSuccess() => _onCreateSuccess(
|
||||||
communityUuid: communityUuid,
|
context,
|
||||||
|
state.space,
|
||||||
|
onSuccess,
|
||||||
|
),
|
||||||
|
CreateSpaceFailure() => _onError(context, state.errorMessage),
|
||||||
|
},
|
||||||
|
child: SpaceDetailsDialog(
|
||||||
|
context: context,
|
||||||
|
title: const SelectableText('Create Space'),
|
||||||
|
spaceModel: SpaceModel.empty(),
|
||||||
|
onSave: (space) {
|
||||||
|
context.read<CreateSpaceBloc>().add(
|
||||||
|
CreateSpace(
|
||||||
|
CreateSpaceParam(
|
||||||
|
communityUuid: communityUuid,
|
||||||
|
space: space,
|
||||||
|
parentUuid: parentUuid,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
communityUuid: communityUuid,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -135,4 +167,14 @@ abstract final class SpaceDetailsDialogHelper {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _onCreateSuccess(
|
||||||
|
BuildContext context,
|
||||||
|
SpaceModel space,
|
||||||
|
void Function(SpaceModel updatedSpaceModel)? onSuccess,
|
||||||
|
) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
onSuccess?.call(space);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/common/edit_chip.dart';
|
import 'package:syncrow_web/common/edit_chip.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/domain/models/subspace.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/button_content_widget.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/button_content_widget.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/space_sub_spaces_dialog.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/subspace_name_display_widget.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/subspace_name_display_widget.dart';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/domain/models/subspace.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/space_details_action_buttons.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/sub_spaces_input.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/presentation/widgets/sub_spaces_input.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/domain/models/subspace.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/space_details/presentation/widgets/subspace_chip.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/domain/models/subspace.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.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/domain/models/subspace.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/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/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/products/domain/models/product.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/product_allocation.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/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/space_details_action_buttons.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:syncrow_web/common/dialog_dropdown.dart';
|
import 'package:syncrow_web/common/dialog_dropdown.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/domain/models/product_allocation.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/subspace.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/data/services/remote_tags_service.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/data/services/remote_tags_service.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/domain/models/tag.dart';
|
||||||
import 'package:syncrow_web/pages/space_management_v2/modules/tags/presentation/bloc/tags_bloc.dart';
|
import 'package:syncrow_web/pages/space_management_v2/modules/tags/presentation/bloc/tags_bloc.dart';
|
||||||
|
@ -34,7 +34,7 @@ class RemoteUpdateSpaceService implements UpdateSpaceService {
|
|||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
final message = e.response?.data as Map<String, dynamic>?;
|
final message = e.response?.data as Map<String, dynamic>?;
|
||||||
final error = message?['error'] as Map<String, dynamic>?;
|
final error = message?['error'] as Map<String, dynamic>?;
|
||||||
final errorMessage = error?['error'] as String? ?? '';
|
final errorMessage = error?['message'] as String? ?? '';
|
||||||
final formattedErrorMessage = [
|
final formattedErrorMessage = [
|
||||||
_defaultErrorMessage,
|
_defaultErrorMessage,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
|
@ -9,34 +9,5 @@ class UpdateSpaceParam {
|
|||||||
final SpaceDetailsModel space;
|
final SpaceDetailsModel space;
|
||||||
final String communityUuid;
|
final String communityUuid;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() => space.toJson();
|
||||||
return {
|
|
||||||
'spaceName': space.spaceName,
|
|
||||||
'icon': space.icon,
|
|
||||||
'subspaces': space.subspaces.map((e) => e._toJson()).toList(),
|
|
||||||
'productAllocations':
|
|
||||||
space.productAllocations.map((e) => e._toJson()).toList(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension _ProductAllocationToJson on ProductAllocation {
|
|
||||||
Map<String, dynamic> _toJson() {
|
|
||||||
final isNewTag = tag.uuid.isEmpty;
|
|
||||||
return <String, dynamic>{
|
|
||||||
if (isNewTag) 'tagName': tag.name else 'tagUuid': tag.uuid,
|
|
||||||
'productUuid': product.uuid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension _SubspaceToJson on Subspace {
|
|
||||||
Map<String, dynamic> _toJson() {
|
|
||||||
final isNewSubspace = uuid.endsWith('-NewTag');
|
|
||||||
return <String, dynamic>{
|
|
||||||
if (!isNewSubspace) 'uuid': uuid,
|
|
||||||
'subspaceName': name,
|
|
||||||
'productAllocations': productAllocations.map((e) => e._toJson()).toList(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/product_allocation.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/domain/models/space_details_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_management_v2/modules/space_details/domain/models/subspace.dart';
|
||||||
|
|
||||||
part 'space_details_model_event.dart';
|
part 'space_details_model_event.dart';
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user