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/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/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_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/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'; import 'package:syncrow_web/utils/navigation_service.dart';
class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> { class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
SpaceModelBloc() : super(SpaceModelInitial()) { SpaceModelBloc() : super(SpaceModelInitial()) {
on<SpaceModelSelectedIdsEvent>(_getSpaceIds); on<SpaceModelSelectedIdsEvent>(_getSpaceIds);
on<LinkSpaceModelEvent>(_handleLinkSpaceModel);
on<ValidateSpaceModelEvent>(_validateLinkSpaceModel);
on<SpaceModelSelectedEvent>((event, emit) { on<SpaceModelSelectedEvent>((event, emit) {
emit(SpaceModelSelectedState(event.selectedIndex)); emit(SpaceModelSelectedState(event.selectedIndex));
}); });
} }
// Future<void> getSpaceIds( List<String> spacesListIds = [];
// 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');
// }
// }
bool hasSelectedSpaces = false; bool hasSelectedSpaces = false;
String validate = '';
Future<void> _getSpaceIds( Future<void> _getSpaceIds(
SpaceModelSelectedIdsEvent event, Emitter<SpaceModelState> emit) async { SpaceModelSelectedIdsEvent event, Emitter<SpaceModelState> emit) async {
@ -40,22 +30,17 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
for (var communityId in spaceBloc.state.selectedCommunities) { for (var communityId in spaceBloc.state.selectedCommunities) {
List<String> spacesList = List<String> spacesList =
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
spacesListIds = spacesList;
for (var spaceId in spacesList) { for (var spaceId in spacesList) {
print('spaceId===$spaceId'); print('spaceId===$spaceId');
} }
} }
// Check if any community has selected spaces
hasSelectedSpaces = hasSelectedSpaces =
spaceBloc.state.selectedCommunities.any((communityId) { spaceBloc.state.selectedCommunities.any((communityId) {
List<String> spacesList = List<String> spacesList =
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
return spacesList.isNotEmpty; return spacesList.isNotEmpty;
}); });
// Optionally, you could emit a state here if you want to rebuild the UI
// emit(SpaceModelSelectionUpdatedState(hasSelectedSpaces));
// Debug output
if (hasSelectedSpaces) { if (hasSelectedSpaces) {
print("At least one space is selected."); print("At least one space is selected.");
} else { } else {
@ -65,4 +50,57 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
print("Error in _getSpaceIds: $e"); 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 {} abstract class SpaceModelEvent {}
class SpaceModelSelectedEvent extends SpaceModelEvent { class SpaceModelSelectedEvent extends SpaceModelEvent {
@ -6,8 +8,15 @@ class SpaceModelSelectedEvent extends SpaceModelEvent {
SpaceModelSelectedEvent(this.selectedIndex); SpaceModelSelectedEvent(this.selectedIndex);
} }
class SpaceModelSelectedIdsEvent extends SpaceModelEvent {}
class LinkSpaceModelEvent extends SpaceModelEvent {
class SpaceModelSelectedIdsEvent 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 SpaceModelInitial extends SpaceModelState {}
class SpaceModelLoading extends SpaceModelState {}
class SpaceModelSelectedState extends SpaceModelState { class SpaceModelSelectedState extends SpaceModelState {
final int selectedIndex; final int selectedIndex;
const SpaceModelSelectedState(this.selectedIndex);
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/material.dart';
import 'package:flutter_bloc/flutter_bloc.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/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_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_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/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/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'; import 'package:syncrow_web/utils/color_manager.dart';
class LinkSpaceModelSpacesDialog extends StatefulWidget { class LinkSpaceModelSpacesDialog extends StatefulWidget {
final SpaceTemplateModel spaceModel; final SpaceTemplateModel spaceModel;
LinkSpaceModelSpacesDialog({super.key, required this.spaceModel});
const LinkSpaceModelSpacesDialog({super.key, required this.spaceModel});
@override @override
State<LinkSpaceModelSpacesDialog> createState() => State<LinkSpaceModelSpacesDialog> createState() =>
@ -19,7 +244,8 @@ class LinkSpaceModelSpacesDialog extends StatefulWidget {
class _LinkSpaceModelSpacesDialogState class _LinkSpaceModelSpacesDialogState
extends State<LinkSpaceModelSpacesDialog> { extends State<LinkSpaceModelSpacesDialog> {
TextEditingController searchController = TextEditingController(); final TextEditingController _searchController = TextEditingController();
bool _isLoading = false;
@override @override
void initState() { void initState() {
@ -34,6 +260,24 @@ class _LinkSpaceModelSpacesDialogState
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
backgroundColor: Colors.white, backgroundColor: Colors.white,
content: SizedBox( content: SizedBox(
width: MediaQuery.of(context).size.width * 0.4,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDialogContent(),
_buildActionButtons(),
],
),
),
);
}
Widget _buildDialogContent() {
return Expanded(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.4, width: MediaQuery.of(context).size.width * 0.4,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -98,9 +342,15 @@ class _LinkSpaceModelSpacesDialogState
), ),
), ),
), ),
],
),
),
),
);
}
// Buttons Widget _buildActionButtons() {
Row( return Row(
children: [ children: [
Expanded( Expanded(
child: Container( child: Container(
@ -138,77 +388,96 @@ class _LinkSpaceModelSpacesDialogState
), ),
), ),
child: _buildButton( child: _buildButton(
"Confirm", ColorsManager.onSecondaryColor, () { "Confirm",
ColorsManager.onSecondaryColor,
() {
final spaceModelBloc = context.read<SpaceModelBloc>(); final spaceModelBloc = context.read<SpaceModelBloc>();
if (!spaceModelBloc.hasSelectedSpaces) { if (!spaceModelBloc.hasSelectedSpaces) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( const SnackBar(
content: content: Text("Please select at least one space")),
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; return;
} }
// Trigger validation
bloc.add(ValidateSpaceModelEvent());
}
void _showLoadingDialog() {
showDialog( showDialog(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (BuildContext context) { 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( return Dialog(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
borderRadius: BorderRadius.circular(20)), child: const Padding(
elevation: 10, padding: EdgeInsets.all(20.0),
backgroundColor: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 30, horizontal: 50),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
CustomLoadingIndicator(), CircularProgressIndicator(),
const SizedBox(height: 20), SizedBox(height: 16),
const Text( Text("Linking in progress..."),
"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();
},
);
});
}),
),
),
],
),
], ],
), ),
), ),
); );
} }
}
// Method to build a detail row // Method to build a detail row
Widget _buildDetailRow(String label, String value) { Widget _buildDetailRow(String label, String value) {
@ -226,8 +495,7 @@ class _LinkSpaceModelSpacesDialogState
Expanded( Expanded(
child: Text( child: Text(
value, value,
style: style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
), ),
), ),
], ],
@ -235,17 +503,15 @@ class _LinkSpaceModelSpacesDialogState
); );
} }
// Button Widget
Widget _buildButton(String text, Color color, VoidCallback onPressed) { Widget _buildButton(String text, Color color, VoidCallback onPressed) {
return InkWell( return InkWell(
onTap: onPressed, onTap: onPressed,
child: Center( child: Center(
child: Text( child: Text(
text, text,
style: TextStyle( style:
color: color, fontWeight: FontWeight.w400, fontSize: 14), TextStyle(color: color, fontWeight: FontWeight.w400, fontSize: 14),
), ),
), ),
); );
} }
}

View File

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

View File

@ -3,9 +3,13 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.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_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_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/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/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_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_product_widget.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
@ -74,15 +78,97 @@ class SpaceModelCardWidget extends StatelessWidget {
children: [ children: [
InkWell( InkWell(
onTap: () { onTap: () {
showDialog(
context: context,
builder: (BuildContext dialogContext) {
return BlocProvider<SpaceModelBloc>(
create: (_) => SpaceModelBloc(),
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( showDialog(
context: context, context: context,
builder: (context) { builder: (BuildContext dialogContext) {
return BlocProvider<SpaceModelBloc>( return const LinkingSuccessful();
create: (_) => SpaceModelBloc(), },
).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( child: LinkSpaceModelSpacesDialog(
spaceModel: model, spaceModel: model,
), ),
),
); );
}, },
); );

View File

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