link space model api integration

This commit is contained in:
mohammad
2025-03-05 14:37:52 +03:00
parent b134823551
commit 215dd9cfa4
8 changed files with 758 additions and 273 deletions

View File

@ -1,36 +1,26 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart';
import 'package:syncrow_web/services/space_model_mang_api.dart';
import 'package:syncrow_web/utils/navigation_service.dart';
class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
SpaceModelBloc() : super(SpaceModelInitial()) {
on<SpaceModelSelectedIdsEvent>(_getSpaceIds);
on<LinkSpaceModelEvent>(_handleLinkSpaceModel);
on<ValidateSpaceModelEvent>(_validateLinkSpaceModel);
on<SpaceModelSelectedEvent>((event, emit) {
emit(SpaceModelSelectedState(event.selectedIndex));
});
}
// Future<void> getSpaceIds(
// SpaceModelSelectedIdsEvent event, Emitter<SpaceModelState> emit) async {
// try {
// BuildContext context = NavigationService.navigatorKey.currentContext!;
// var spaceBloc = context.read<SpaceTreeBloc>();
// for (var communityId in spaceBloc.state.selectedCommunities) {
// List<String> spacesList =
// spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
// for (var spaceId in spacesList) {
// print('spaceId===$spaceId');
// }
// }
// } catch (e) {
// print('Error fetching space IDs: $e');
// }
// }
List<String> spacesListIds = [];
bool hasSelectedSpaces = false;
String validate = '';
Future<void> _getSpaceIds(
SpaceModelSelectedIdsEvent event, Emitter<SpaceModelState> emit) async {
@ -40,22 +30,17 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
for (var communityId in spaceBloc.state.selectedCommunities) {
List<String> spacesList =
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
spacesListIds = spacesList;
for (var spaceId in spacesList) {
print('spaceId===$spaceId');
}
}
// Check if any community has selected spaces
hasSelectedSpaces =
spaceBloc.state.selectedCommunities.any((communityId) {
List<String> spacesList =
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
return spacesList.isNotEmpty;
});
// Optionally, you could emit a state here if you want to rebuild the UI
// emit(SpaceModelSelectionUpdatedState(hasSelectedSpaces));
// Debug output
if (hasSelectedSpaces) {
print("At least one space is selected.");
} else {
@ -65,4 +50,57 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
print("Error in _getSpaceIds: $e");
}
}
Future<void> _handleLinkSpaceModel(
LinkSpaceModelEvent event,
Emitter<SpaceModelState> emit,
) async {
emit(SpaceModelLoading());
try {
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
await SpaceModelManagementApi().linkSpaceModel(
spaceModelUuid: event.selectedSpaceMode!,
projectId: projectUuid,
spaceUuids: spacesListIds,
isOverWrite: event.isOverWrite);
emit(SpaceModelLinkSuccess());
} on DioException catch (e) {
final errorMessage = _parseDioError(e);
emit(SpaceModelOperationFailure(errorMessage));
} catch (e) {
emit(SpaceModelOperationFailure('Unexpected error: $e'));
}
}
Future<void> _validateLinkSpaceModel(
ValidateSpaceModelEvent event,
Emitter<SpaceModelState> emit,
) async {
emit(SpaceModelLoading());
try {
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
await SpaceModelManagementApi().validateSpaceModel(
projectUuid,
spacesListIds,
);
emit(SpaceValidationSuccess());
} on DioException catch (e) {
final errorMessage = _parseDioError(e);
if (errorMessage ==
'Selected spaces already have linked space model / sub-spaces and devices') {
emit(const AlreadyHaveLinkedState());
} else {
emit(SpaceModelOperationFailure(errorMessage));
}
} catch (e) {
emit(SpaceModelOperationFailure('Unexpected error: $e'));
}
}
String _parseDioError(DioException e) {
if (e.response?.data is Map<String, dynamic>) {
return e.response!.data['error']['message'] ?? 'Unknown error occurred';
}
return e.message ?? 'Network request failed';
}
}

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
abstract class SpaceModelEvent {}
class SpaceModelSelectedEvent extends SpaceModelEvent {
@ -6,8 +8,15 @@ class SpaceModelSelectedEvent extends SpaceModelEvent {
SpaceModelSelectedEvent(this.selectedIndex);
}
class SpaceModelSelectedIdsEvent extends SpaceModelEvent {}
class SpaceModelSelectedIdsEvent extends SpaceModelEvent {
class LinkSpaceModelEvent extends SpaceModelEvent {
final String? selectedSpaceMode;
final bool isOverWrite;
LinkSpaceModelEvent({this.selectedSpaceMode, this.isOverWrite = false});
}
class ValidateSpaceModelEvent extends SpaceModelEvent {
BuildContext? context;
ValidateSpaceModelEvent({this.context});
}

View File

@ -1,9 +1,35 @@
abstract class SpaceModelState {}
abstract class SpaceModelState {
const SpaceModelState();
}
class SpaceModelInitial extends SpaceModelState {}
class SpaceModelLoading extends SpaceModelState {}
class SpaceModelSelectedState extends SpaceModelState {
final int selectedIndex;
SpaceModelSelectedState(this.selectedIndex);
const SpaceModelSelectedState(this.selectedIndex);
}
class SpaceModelSelectionUpdated extends SpaceModelState {
final bool hasSelectedSpaces;
const SpaceModelSelectionUpdated(this.hasSelectedSpaces);
}
class SpaceValidationSuccess extends SpaceModelState {}
class SpaceModelLinkSuccess extends SpaceModelState {}
class ValidationError extends SpaceModelState {
final String message;
const ValidationError(this.message);
}
class SpaceModelOperationFailure extends SpaceModelState {
final String message;
const SpaceModelOperationFailure(this.message);
}
class AlreadyHaveLinkedState extends SpaceModelState {
const AlreadyHaveLinkedState();
}

View File

@ -1,16 +1,241 @@
// import 'package:flutter/material.dart';
// import 'package:flutter_bloc/flutter_bloc.dart';
// import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
// import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart';
// import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart';
// import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
// import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart';
// import 'package:syncrow_web/utils/color_manager.dart';
// class LinkSpaceModelSpacesDialog extends StatefulWidget {
// final SpaceTemplateModel spaceModel;
// LinkSpaceModelSpacesDialog({super.key, required this.spaceModel});
// @override
// State<LinkSpaceModelSpacesDialog> createState() =>
// _LinkSpaceModelSpacesDialogState();
// }
// class _LinkSpaceModelSpacesDialogState
// extends State<LinkSpaceModelSpacesDialog> {
// TextEditingController searchController = TextEditingController();
// @override
// void initState() {
// context.read<SpaceModelBloc>().add(SpaceModelSelectedIdsEvent());
// super.initState();
// }
// @override
// Widget build(BuildContext context) {
// return AlertDialog(
// contentPadding: EdgeInsets.zero,
// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
// backgroundColor: Colors.white,
// content: SizedBox(
// width: MediaQuery.of(context).size.width * 0.4,
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Expanded(
// child: Padding(
// padding: const EdgeInsets.all(15.0),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// const Center(
// child: Text(
// "Link Space Model to Spaces",
// style: TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.bold,
// color: Colors.blueAccent,
// ),
// ),
// ),
// const Divider(),
// const SizedBox(height: 16),
// _buildDetailRow(
// "Space model name:", widget.spaceModel.modelName),
// _buildDetailRow("Creation date and time:",
// widget.spaceModel.createdAt.toString()),
// _buildDetailRow("Created by:", "Admin"),
// const SizedBox(height: 12),
// const Text(
// "Link to:",
// style: TextStyle(fontWeight: FontWeight.bold),
// ),
// const Text(
// "Please select all the spaces where you would like to link the Routine.",
// style: TextStyle(fontSize: 12, color: Colors.grey),
// ),
// const SizedBox(height: 8),
// Expanded(
// child: SizedBox(
// child: Column(
// children: [
// Expanded(
// flex: 7,
// child: Container(
// color: ColorsManager.whiteColors,
// child: SpaceTreeView(
// isSide: true,
// onSelect: () {
// context.read<SpaceModelBloc>().add(
// SpaceModelSelectedIdsEvent());
// })))
// ],
// ),
// ),
// ),
// const SizedBox(
// height: 20,
// ),
// ],
// ),
// ),
// ),
// // Buttons
// Row(
// children: [
// Expanded(
// child: Container(
// height: 50,
// decoration: const BoxDecoration(
// border: Border(
// right: BorderSide(
// color: ColorsManager.grayColor,
// width: 0.5,
// ),
// top: BorderSide(
// color: ColorsManager.grayColor,
// width: 1,
// ),
// ),
// ),
// child: _buildButton("Cancel", Colors.grey, () {
// Navigator.of(context).pop();
// }),
// ),
// ),
// Expanded(
// child: Container(
// height: 50,
// decoration: const BoxDecoration(
// border: Border(
// left: BorderSide(
// color: ColorsManager.grayColor,
// width: 0.5,
// ),
// top: BorderSide(
// color: ColorsManager.grayColor,
// width: 1.0,
// ),
// ),
// ),
// child: _buildButton(
// "Confirm", ColorsManager.onSecondaryColor, () {
// final spaceModelBloc = context.read<SpaceModelBloc>();
// if (!spaceModelBloc.hasSelectedSpaces) {
// ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(
// content:
// Text("Please select at least one space")),
// );
// return;
// } else {
// // spaceModelBloc.add(LinkSpaceModelEvent(
// // selectedSpaceMode: widget.spaceModel.uuid));
// spaceModelBloc.add(ValidateSpaceModelEvent(context: context));
// }
// Future.delayed(const Duration(seconds: 3), () {
// Navigator.of(context).pop();
// Navigator.of(context).pop();
// // showDialog(
// // context: context,
// // builder: (BuildContext dialogContext) {
// // return const LinkingSuccessful();
// // },
// // );
// showDialog(
// context: context,
// builder: (BuildContext dialogContext) {
// return const ConfirmOverwriteDialog();
// },
// );
// });
// }),
// ),
// ),
// ],
// ),
// ],
// ),
// ),
// );
// }
// // Method to build a detail row
// Widget _buildDetailRow(String label, String value) {
// return Padding(
// padding: const EdgeInsets.symmetric(vertical: 4),
// child: Row(
// children: [
// Expanded(
// child: Text(
// label,
// style: TextStyle(fontWeight: FontWeight.bold),
// ),
// ),
// const SizedBox(width: 8),
// Expanded(
// child: Text(
// value,
// style:
// TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
// ),
// ),
// ],
// ),
// );
// }
// Widget _buildButton(String text, Color color, VoidCallback onPressed) {
// return InkWell(
// onTap: onPressed,
// child: Center(
// child: Text(
// text,
// style: TextStyle(
// color: color, fontWeight: FontWeight.w400, fontSize: 14),
// ),
// ),
// );
// }
// }
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class LinkSpaceModelSpacesDialog extends StatefulWidget {
final SpaceTemplateModel spaceModel;
LinkSpaceModelSpacesDialog({super.key, required this.spaceModel});
const LinkSpaceModelSpacesDialog({super.key, required this.spaceModel});
@override
State<LinkSpaceModelSpacesDialog> createState() =>
@ -19,7 +244,8 @@ class LinkSpaceModelSpacesDialog extends StatefulWidget {
class _LinkSpaceModelSpacesDialogState
extends State<LinkSpaceModelSpacesDialog> {
TextEditingController searchController = TextEditingController();
final TextEditingController _searchController = TextEditingController();
bool _isLoading = false;
@override
void initState() {
@ -39,213 +265,253 @@ class _LinkSpaceModelSpacesDialogState
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Center(
child: Text(
"Link Space Model to Spaces",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.blueAccent,
),
),
),
const Divider(),
const SizedBox(height: 16),
_buildDetailRow(
"Space model name:", widget.spaceModel.modelName),
_buildDetailRow("Creation date and time:",
widget.spaceModel.createdAt.toString()),
_buildDetailRow("Created by:", "Admin"),
const SizedBox(height: 12),
const Text(
"Link to:",
style: TextStyle(fontWeight: FontWeight.bold),
),
const Text(
"Please select all the spaces where you would like to link the Routine.",
style: TextStyle(fontSize: 12, color: Colors.grey),
),
const SizedBox(height: 8),
Expanded(
child: SizedBox(
child: Column(
children: [
Expanded(
flex: 7,
child: Container(
color: ColorsManager.whiteColors,
child: SpaceTreeView(
isSide: true,
onSelect: () {
context.read<SpaceModelBloc>().add(
SpaceModelSelectedIdsEvent());
})))
],
),
),
),
const SizedBox(
height: 20,
),
],
),
),
),
// Buttons
Row(
children: [
Expanded(
child: Container(
height: 50,
decoration: const BoxDecoration(
border: Border(
right: BorderSide(
color: ColorsManager.grayColor,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.grayColor,
width: 1,
),
),
),
child: _buildButton("Cancel", Colors.grey, () {
Navigator.of(context).pop();
}),
),
),
Expanded(
child: Container(
height: 50,
decoration: const BoxDecoration(
border: Border(
left: BorderSide(
color: ColorsManager.grayColor,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.grayColor,
width: 1.0,
),
),
),
child: _buildButton(
"Confirm", ColorsManager.onSecondaryColor, () {
final spaceModelBloc = context.read<SpaceModelBloc>();
if (!spaceModelBloc.hasSelectedSpaces) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content:
Text("Please select at least one space")),
);
return;
}
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
elevation: 10,
backgroundColor: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 30, horizontal: 50),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CustomLoadingIndicator(),
const SizedBox(height: 20),
const Text(
"Linking in progress",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
],
),
),
);
},
).then(
(value) {},
);
Future.delayed(const Duration(seconds: 3), () {
Navigator.of(context).pop();
Navigator.of(context).pop();
// showDialog(
// context: context,
// builder: (BuildContext dialogContext) {
// return const LinkingSuccessful();
// },
// );
showDialog(
context: context,
builder: (BuildContext dialogContext) {
return const ConfirmOverwriteDialog();
},
);
});
}),
),
),
],
),
_buildDialogContent(),
_buildActionButtons(),
],
),
),
);
}
// Method to build a detail row
Widget _buildDetailRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
Expanded(
child: Text(
label,
style: TextStyle(fontWeight: FontWeight.bold),
),
Widget _buildDialogContent() {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.4,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Center(
child: Text(
"Link Space Model to Spaces",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.blueAccent,
),
),
),
const Divider(),
const SizedBox(height: 16),
_buildDetailRow(
"Space model name:", widget.spaceModel.modelName),
_buildDetailRow("Creation date and time:",
widget.spaceModel.createdAt.toString()),
_buildDetailRow("Created by:", "Admin"),
const SizedBox(height: 12),
const Text(
"Link to:",
style: TextStyle(fontWeight: FontWeight.bold),
),
const Text(
"Please select all the spaces where you would like to link the Routine.",
style: TextStyle(fontSize: 12, color: Colors.grey),
),
const SizedBox(height: 8),
Expanded(
child: SizedBox(
child: Column(
children: [
Expanded(
flex: 7,
child: Container(
color: ColorsManager.whiteColors,
child: SpaceTreeView(
isSide: true,
onSelect: () {
context.read<SpaceModelBloc>().add(
SpaceModelSelectedIdsEvent());
})))
],
),
),
),
const SizedBox(
height: 20,
),
],
),
),
),
],
),
const SizedBox(width: 8),
Expanded(
child: Text(
value,
style:
TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
),
),
],
),
),
);
}
// Button Widget
Widget _buildButton(String text, Color color, VoidCallback onPressed) {
return InkWell(
onTap: onPressed,
child: Center(
child: Text(
text,
style: TextStyle(
color: color, fontWeight: FontWeight.w400, fontSize: 14),
Widget _buildActionButtons() {
return Row(
children: [
Expanded(
child: Container(
height: 50,
decoration: const BoxDecoration(
border: Border(
right: BorderSide(
color: ColorsManager.grayColor,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.grayColor,
width: 1,
),
),
),
child: _buildButton("Cancel", Colors.grey, () {
Navigator.of(context).pop();
}),
),
),
Expanded(
child: Container(
height: 50,
decoration: const BoxDecoration(
border: Border(
left: BorderSide(
color: ColorsManager.grayColor,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.grayColor,
width: 1.0,
),
),
),
child: _buildButton(
"Confirm",
ColorsManager.onSecondaryColor,
() {
final spaceModelBloc = context.read<SpaceModelBloc>();
if (!spaceModelBloc.hasSelectedSpaces) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Please select at least one space")),
);
return;
} else {
spaceModelBloc.add(ValidateSpaceModelEvent(context: context));
}
},
),
),
),
],
);
}
void _handleConfirm() {
final bloc = context.read<SpaceModelBloc>();
if (!bloc.hasSelectedSpaces) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please select at least one space")),
);
return;
}
// Trigger validation
bloc.add(ValidateSpaceModelEvent());
}
void _showLoadingDialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => const _LoadingDialog(),
);
}
void _handleValidationSuccess() {
Navigator.of(context).pop(); // Close loading dialog
// Show overwrite confirmation
showDialog(
context: context,
builder: (context) => const ConfirmOverwriteDialog(),
).then((_) {
// Close main dialog after confirmation
if (mounted) Navigator.of(context).pop();
});
}
void _handleValidationError(String message) {
Navigator.of(context).pop(); // Close loading dialog
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
void _handleCancel() {
if (mounted) Navigator.of(context).pop();
}
// Rest of your helper methods (_buildDetailRow, _buildButton, etc.)
}
class _LoadingDialog extends StatelessWidget {
const _LoadingDialog();
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: const Padding(
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text("Linking in progress..."),
],
),
),
);
}
}
// Method to build a detail row
Widget _buildDetailRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
children: [
Expanded(
child: Text(
label,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
const SizedBox(width: 8),
Expanded(
child: Text(
value,
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
),
),
],
),
);
}
Widget _buildButton(String text, Color color, VoidCallback onPressed) {
return InkWell(
onTap: onPressed,
child: Center(
child: Text(
text,
style:
TextStyle(color: color, fontWeight: FontWeight.w400, fontSize: 14),
),
),
);
}

View File

@ -1,24 +1,27 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
void showOverwriteDialog(BuildContext context) {
void showOverwriteDialog(
BuildContext context, SpaceModelBloc bloc, SpaceTemplateModel model) {
showDialog(
context: context,
barrierDismissible: false,
barrierDismissible: false,
builder: (BuildContext context) {
return Container(
return SizedBox(
child: Dialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
elevation: 10,
backgroundColor: Colors.white,
child: Container(
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 30, horizontal: 20),
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Title
const Text(
"Overwrite",
style: TextStyle(
@ -27,15 +30,13 @@ void showOverwriteDialog(BuildContext context) {
color: Colors.black,
),
),
SizedBox(height: 15),
// Description
const SizedBox(height: 15),
const Text(
"Are you sure you want to overwrite?",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
textAlign: TextAlign.center,
),
SizedBox(height: 5),
const SizedBox(height: 5),
Text(
"Selected spaces already have linked space model / sub-spaces and devices",
style: TextStyle(
@ -44,25 +45,22 @@ void showOverwriteDialog(BuildContext context) {
),
textAlign: TextAlign.center,
),
SizedBox(height: 25),
// Buttons
const SizedBox(height: 25),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// Cancel Button
Expanded(
child: ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 14),
padding: const EdgeInsets.symmetric(vertical: 14),
backgroundColor: Colors.grey[200],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: Text(
child: const Text(
"Cancel",
style: TextStyle(
fontSize: 16,
@ -72,24 +70,24 @@ void showOverwriteDialog(BuildContext context) {
),
),
),
SizedBox(width: 10),
// OK Button
const SizedBox(width: 10),
Expanded(
child: ElevatedButton(
onPressed: () {
bloc.add(LinkSpaceModelEvent(
isOverWrite: true,
selectedSpaceMode: model.uuid));
Navigator.of(context).pop();
// Add action for OK button
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 14),
padding: const EdgeInsets.symmetric(vertical: 14),
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 3,
),
child: Text(
child: const Text(
"OK",
style: TextStyle(
fontSize: 16,

View File

@ -3,9 +3,13 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_product_widget.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart';
@ -74,14 +78,96 @@ class SpaceModelCardWidget extends StatelessWidget {
children: [
InkWell(
onTap: () {
showDialog(
context: context,
builder: (context) {
builder: (BuildContext dialogContext) {
return BlocProvider<SpaceModelBloc>(
create: (_) => SpaceModelBloc(),
child: LinkSpaceModelSpacesDialog(
spaceModel: model,
child: BlocListener<SpaceModelBloc,
SpaceModelState>(
listener: (context, state) {
final _bloc =
BlocProvider.of<SpaceModelBloc>(
context);
if (state is SpaceModelLoading) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20)),
elevation: 10,
backgroundColor: Colors.white,
child: Padding(
padding:
const EdgeInsets.symmetric(
vertical: 30,
horizontal: 50),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CustomLoadingIndicator(),
const SizedBox(height: 20),
const Text(
"Linking in progress",
style: TextStyle(
fontSize: 16,
fontWeight:
FontWeight.w500,
color: Colors.black87,
),
),
],
),
),
);
},
);
} else if (state
is AlreadyHaveLinkedState) {
Navigator.of(dialogContext).pop();
showOverwriteDialog(
context, _bloc, model);
} else if (state
is SpaceValidationSuccess) {
_bloc.add(LinkSpaceModelEvent(
isOverWrite: false,
selectedSpaceMode: model.uuid));
Future.delayed(const Duration(seconds: 1),
() {
Navigator.of(dialogContext).pop();
Navigator.of(dialogContext).pop();
Navigator.of(dialogContext).pop();
});
showDialog(
context: context,
builder: (BuildContext dialogContext) {
return const LinkingSuccessful();
},
).then((v) {
Future.delayed(
const Duration(seconds: 2), () {
Navigator.of(dialogContext).pop();
});
});
} else if (state is SpaceModelLinkSuccess) {
Navigator.of(dialogContext).pop();
Navigator.of(dialogContext).pop();
showDialog(
context: context,
builder: (BuildContext dialogContext) {
return const LinkingSuccessful();
},
);
}
},
child: LinkSpaceModelSpacesDialog(
spaceModel: model,
),
),
);
},

View File

@ -60,4 +60,40 @@ class SpaceModelManagementApi {
);
return response;
}
Future linkSpaceModel(
{required String spaceModelUuid,
required String projectId,
required List<String> spaceUuids,
required bool isOverWrite}) async {
print(spaceModelUuid);
print(projectId);
print(spaceUuids);
print(isOverWrite);
final response = await HTTPService().post(
path: ApiEndpoints.linkSpaceModel
.replaceAll('{projectId}', projectId)
.replaceAll('{spaceModelUuid}', spaceModelUuid),
showServerMessage: true,
body: {"spaceUuids": spaceUuids, "overwrite": isOverWrite},
expectedResponseModel: (json) {
return json;
},
);
return response;
}
Future validateSpaceModel(String projectId, List<String> spaceUuids) async {
final response = await HTTPService().post(
path:
ApiEndpoints.validateSpaceModel.replaceAll('{projectId}', projectId),
showServerMessage: true,
body: {"spacesUuids": spaceUuids},
expectedResponseModel: (json) {
return json;
},
);
return response;
}
}

View File

@ -9,15 +9,19 @@ abstract class ApiEndpoints {
static const String sendOtp = '/authentication/user/send-otp';
static const String verifyOtp = '/authentication/user/verify-otp';
static const String getRegion = '/region';
static const String visitorPassword = '/projects/{projectId}/visitor-password';
static const String getDevices = '/projects/{projectId}/visitor-password/devices';
static const String visitorPassword =
'/projects/{projectId}/visitor-password';
static const String getDevices =
'/projects/{projectId}/visitor-password/devices';
static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time';
static const String sendOnlineOneTime =
'/visitor-password/temporary-password/online/one-time';
static const String sendOnlineMultipleTime =
'/visitor-password/temporary-password/online/multiple-time';
//offline Password
static const String sendOffLineOneTime = '/visitor-password/temporary-password/offline/one-time';
static const String sendOffLineOneTime =
'/visitor-password/temporary-password/offline/one-time';
static const String sendOffLineMultipleTime =
'/visitor-password/temporary-password/offline/multiple-time';
@ -39,32 +43,45 @@ abstract class ApiEndpoints {
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
// Space Module
static const String createSpace = '/projects/{projectId}/communities/{communityId}/spaces';
static const String listSpaces = '/projects/{projectId}/communities/{communityId}/spaces';
static const String createSpace =
'/projects/{projectId}/communities/{communityId}/spaces';
static const String listSpaces =
'/projects/{projectId}/communities/{communityId}/spaces';
static const String deleteSpace =
'/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
static const String updateSpace =
'/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
static const String getSpace = '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
static const String getSpaceHierarchy = '/projects/{projectId}/communities/{communityId}/spaces';
static const String getSpace =
'/projects/{projectId}/communities/{communityId}/spaces/{spaceId}';
static const String getSpaceHierarchy =
'/projects/{projectId}/communities/{communityId}/spaces';
// Community Module
static const String createCommunity = '/projects/{projectId}/communities';
static const String getCommunityList = '/projects/{projectId}/communities';
static const String getCommunityById = '/projects/{projectId}/communities/{communityId}';
static const String updateCommunity = '/projects/{projectId}/communities/{communityId}';
static const String deleteCommunity = '/projects/{projectId}communities/{communityId}';
static const String getUserCommunities = '/projects/{projectId}/communities/user/{userUuid}';
static const String createUserCommunity = '/projects/{projectId}/communities/user';
static const String getCommunityById =
'/projects/{projectId}/communities/{communityId}';
static const String updateCommunity =
'/projects/{projectId}/communities/{communityId}';
static const String deleteCommunity =
'/projects/{projectId}communities/{communityId}';
static const String getUserCommunities =
'/projects/{projectId}/communities/user/{userUuid}';
static const String createUserCommunity =
'/projects/{projectId}/communities/user';
static const String getDeviceLogsByDate =
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}';
static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}';
static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}';
static const String getScheduleByDeviceId =
'/schedule/{deviceUuid}?category={category}';
static const String deleteScheduleByDeviceId =
'/schedule/{deviceUuid}/{scheduleUuid}';
static const String updateScheduleByDeviceId =
'/schedule/enable/{deviceUuid}';
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
static const String powerClamp = '/device/{powerClampUuid}/power-clamp/status';
static const String powerClamp =
'/device/{powerClampUuid}/power-clamp/status';
//product
static const String listProducts = '/products';
@ -75,7 +92,8 @@ abstract class ApiEndpoints {
static const String createAutomation = '/automation';
static const String getUnitScenes =
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/scenes';
static const String getAutomationDetails = '/automation/details/{automationId}';
static const String getAutomationDetails =
'/automation/details/{automationId}';
static const String getScene = '/scene/tap-to-run/{sceneId}';
static const String deleteScene = '/scene/tap-to-run/{sceneId}';
@ -87,8 +105,15 @@ abstract class ApiEndpoints {
//space model
static const String listSpaceModels = '/projects/{projectId}/space-models';
static const String createSpaceModel = '/projects/{projectId}/space-models';
static const String getSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}';
static const String updateSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}';
static const String getSpaceModel =
'/projects/{projectId}/space-models/{spaceModelUuid}';
static const String updateSpaceModel =
'/projects/{projectId}/space-models/{spaceModelUuid}';
static const String linkSpaceModel =
'/projects/{projectId}/space-models/{spaceModelUuid}/spaces/link';
static const String validateSpaceModel =
'/projects/{projectId}/spaces/validate';
static const String roleTypes = '/role/types';
static const String permission = '/permission/{roleUuid}';
@ -99,7 +124,8 @@ abstract class ApiEndpoints {
static const String getUserById = '/projects/{projectUuid}/user/{userUuid}';
static const String editUser = '/invite-user/{inviteUserUuid}';
static const String deleteUser = '/invite-user/{inviteUserUuid}';
static const String changeUserStatus = '/invite-user/{invitedUserUuid}/disable';
static const String changeUserStatus =
'/invite-user/{invitedUserUuid}/disable';
static const String terms = '/terms';
static const String policy = '/policy';
static const String userAgreements = '/user/agreements/web/{userUuid}';