mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-14 17:25:50 +00:00
Compare commits
18 Commits
bugfix/fix
...
SP-1221-FE
Author | SHA1 | Date | |
---|---|---|---|
41605bef6b | |||
fd24d6bd27 | |||
5ea29efaf5 | |||
70cb12236b | |||
9f75ce817e | |||
aa23daa0b4 | |||
61f0c3ad2b | |||
553c77d1e3 | |||
27fef7ddaa | |||
010176cc25 | |||
d08a1d1037 | |||
e634154fb3 | |||
c0f59aba61 | |||
7ee7681e09 | |||
57c5f4752c | |||
ad4f2ae382 | |||
eafb811d2e | |||
2d0dcc41df |
6
assets/icons/delete_space_model.svg
Normal file
6
assets/icons/delete_space_model.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.4 2.10938H11.7333V1.58203C11.7333 0.709699 11.0156 0 10.1333 0H5.86667C4.98443 0 4.26667 0.709699 4.26667 1.58203V2.10938H1.6C0.71776 2.10938 0 2.81907 0 3.69141C0 4.392 0.463111 4.9873 1.1024 5.19472L2.05369 16.5493C2.1222 17.3628 2.82258 18 3.64814 18H12.3519C13.1775 18 13.8778 17.3628 13.9464 16.5491L14.8976 5.19469C15.5369 4.9873 16 4.392 16 3.69141C16 2.81907 15.2822 2.10938 14.4 2.10938ZM5.33333 1.58203C5.33333 1.29125 5.57259 1.05469 5.86667 1.05469H10.1333C10.4274 1.05469 10.6667 1.29125 10.6667 1.58203V2.10938H5.33333V1.58203ZM12.8833 16.4618C12.8605 16.7329 12.6271 16.9453 12.3519 16.9453H3.64814C3.37298 16.9453 3.13952 16.7329 3.11673 16.462L2.17934 5.27344H13.8207L12.8833 16.4618ZM14.4 4.21875H1.6C1.30592 4.21875 1.06667 3.98218 1.06667 3.69141C1.06667 3.40063 1.30592 3.16406 1.6 3.16406H14.4C14.6941 3.16406 14.9333 3.40063 14.9333 3.69141C14.9333 3.98218 14.6941 4.21875 14.4 4.21875Z" fill="#999999"/>
|
||||
<path d="M5.86561 15.3307L5.33228 6.82286C5.31404 6.53215 5.05957 6.31106 4.76698 6.32916C4.47297 6.3472 4.24943 6.59744 4.26764 6.88811L4.80097 15.396C4.8185 15.6756 5.05331 15.8907 5.33278 15.8907C5.64165 15.8907 5.88456 15.6335 5.86561 15.3307Z" fill="#999999"/>
|
||||
<path d="M7.99989 6.32812C7.70534 6.32812 7.46655 6.56423 7.46655 6.85547V15.3633C7.46655 15.6545 7.70534 15.8906 7.99989 15.8906C8.29443 15.8906 8.53322 15.6545 8.53322 15.3633V6.85547C8.53322 6.56423 8.29443 6.32812 7.99989 6.32812Z" fill="#999999"/>
|
||||
<path d="M11.233 6.32915C10.9396 6.31112 10.6859 6.53215 10.6677 6.82285L10.1343 15.3307C10.1162 15.6213 10.3397 15.8716 10.6337 15.8896C10.9278 15.9076 11.1808 15.6865 11.199 15.3959L11.7323 6.8881C11.7505 6.5974 11.527 6.34715 11.233 6.32915Z" fill="#999999"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
@ -20,15 +20,22 @@ class DialogTextfieldDropdown extends StatefulWidget {
|
||||
|
||||
class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
bool _isOpen = false;
|
||||
late OverlayEntry _overlayEntry;
|
||||
OverlayEntry? _overlayEntry;
|
||||
final TextEditingController _controller = TextEditingController();
|
||||
late List<String> _filteredItems; // Filtered items list
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
List<String> _filteredItems = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller.text = widget.initialValue ?? 'Select Tag';
|
||||
_filteredItems = List.from(widget.items); // Initialize filtered items
|
||||
_controller.text = widget.initialValue ?? '';
|
||||
_filteredItems = List.from(widget.items);
|
||||
|
||||
_focusNode.addListener(() {
|
||||
if (!_focusNode.hasFocus) {
|
||||
_closeDropdown();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _toggleDropdown() {
|
||||
@ -41,13 +48,16 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
|
||||
void _openDropdown() {
|
||||
_overlayEntry = _createOverlayEntry();
|
||||
Overlay.of(context).insert(_overlayEntry);
|
||||
Overlay.of(context).insert(_overlayEntry!);
|
||||
_isOpen = true;
|
||||
}
|
||||
|
||||
void _closeDropdown() {
|
||||
_overlayEntry.remove();
|
||||
_isOpen = false;
|
||||
if (_isOpen && _overlayEntry != null) {
|
||||
_overlayEntry!.remove();
|
||||
_overlayEntry = null;
|
||||
_isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
OverlayEntry _createOverlayEntry() {
|
||||
@ -58,9 +68,7 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
return OverlayEntry(
|
||||
builder: (context) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
_closeDropdown();
|
||||
},
|
||||
onTap: _closeDropdown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
child: Stack(
|
||||
children: [
|
||||
@ -72,40 +80,44 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
elevation: 4.0,
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
constraints: const BoxConstraints(
|
||||
maxHeight: 200.0,
|
||||
),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: _filteredItems.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _filteredItems[index];
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: ColorsManager.lightGrayBorderColor,
|
||||
width: 1.0,
|
||||
constraints: const BoxConstraints(maxHeight: 200.0),
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setStateDropdown) {
|
||||
return ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: _filteredItems.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _filteredItems[index];
|
||||
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: ColorsManager.lightGrayBorderColor,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: ListTile(
|
||||
title: Text(item,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(
|
||||
color: ColorsManager.textPrimaryColor)),
|
||||
onTap: () {
|
||||
_controller.text = item;
|
||||
widget.onSelected(item);
|
||||
setState(() {
|
||||
_filteredItems
|
||||
.remove(item); // Remove selected item
|
||||
});
|
||||
_closeDropdown();
|
||||
},
|
||||
),
|
||||
child: ListTile(
|
||||
title: Text(item,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(
|
||||
color: ColorsManager
|
||||
.textPrimaryColor)),
|
||||
onTap: () {
|
||||
_controller.text = item;
|
||||
widget.onSelected(item);
|
||||
setState(() {
|
||||
_filteredItems
|
||||
.remove(item); // Remove selected item
|
||||
});
|
||||
_closeDropdown();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -122,7 +134,8 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: _toggleDropdown,
|
||||
onTap: () => FocusScope.of(context).unfocus(),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
||||
decoration: BoxDecoration(
|
||||
@ -135,23 +148,26 @@ class _DialogTextfieldDropdownState extends State<DialogTextfieldDropdown> {
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
controller: _controller,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_filteredItems = widget.items
|
||||
.where((item) =>
|
||||
item.toLowerCase().contains(value.toLowerCase()))
|
||||
.toList(); // Filter items dynamically
|
||||
});
|
||||
focusNode: _focusNode,
|
||||
onFieldSubmitted: (value) {
|
||||
widget.onSelected(value);
|
||||
_closeDropdown();
|
||||
},
|
||||
onTapOutside: (event) {
|
||||
widget.onSelected(_controller.text);
|
||||
_closeDropdown();
|
||||
},
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter or Select tag',
|
||||
hintText: 'Enter or Select a tag',
|
||||
border: InputBorder.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(Icons.arrow_drop_down),
|
||||
GestureDetector(
|
||||
onTap: _toggleDropdown,
|
||||
child: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -10,9 +10,12 @@ import 'package:syncrow_web/pages/auth/model/region_model.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.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_event.dart';
|
||||
import 'package:syncrow_web/services/auth_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
@ -32,8 +35,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
|
||||
////////////////////////////// forget password //////////////////////////////////
|
||||
final TextEditingController forgetEmailController = TextEditingController();
|
||||
final TextEditingController forgetPasswordController =
|
||||
TextEditingController();
|
||||
final TextEditingController forgetPasswordController = TextEditingController();
|
||||
final TextEditingController forgetOtp = TextEditingController();
|
||||
final forgetFormKey = GlobalKey<FormState>();
|
||||
final forgetEmailKey = GlobalKey<FormState>();
|
||||
@ -50,8 +52,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
return;
|
||||
}
|
||||
_remainingTime = 1;
|
||||
add(UpdateTimerEvent(
|
||||
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
try {
|
||||
forgetEmailValidate = '';
|
||||
_remainingTime = (await AuthenticationAPI.sendOtp(
|
||||
@ -88,8 +89,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
_timer?.cancel();
|
||||
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
||||
} else {
|
||||
add(UpdateTimerEvent(
|
||||
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -99,8 +99,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
||||
}
|
||||
|
||||
Future<void> changePassword(
|
||||
ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||
Future<void> changePassword(ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||
emit(LoadingForgetState());
|
||||
try {
|
||||
var response = await AuthenticationAPI.verifyOtp(
|
||||
@ -116,8 +115,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
String errorMessage =
|
||||
errorData['error']['message'] ?? 'something went wrong';
|
||||
String errorMessage = errorData['error']['message'] ?? 'something went wrong';
|
||||
validate = errorMessage;
|
||||
emit(AuthInitialState());
|
||||
}
|
||||
@ -131,9 +129,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
|
||||
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
||||
emit(TimerState(
|
||||
isButtonEnabled: event.isButtonEnabled,
|
||||
remainingTime: event.remainingTime));
|
||||
emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime));
|
||||
}
|
||||
|
||||
///////////////////////////////////// login /////////////////////////////////////
|
||||
@ -183,15 +179,13 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
|
||||
if (token.accessTokenIsNotEmpty) {
|
||||
FlutterSecureStorage storage = const FlutterSecureStorage();
|
||||
await storage.write(
|
||||
key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||
await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||
const FlutterSecureStorage().write(
|
||||
key: UserModel.userUuidKey,
|
||||
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
||||
user = UserModel.fromToken(token);
|
||||
loginEmailController.clear();
|
||||
loginPasswordController.clear();
|
||||
debugPrint("token " + token.accessToken);
|
||||
emit(LoginSuccess());
|
||||
} else {
|
||||
emit(const LoginFailure(error: 'Something went wrong'));
|
||||
@ -342,14 +336,12 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
static Future<String> getTokenAndValidate() async {
|
||||
try {
|
||||
const storage = FlutterSecureStorage();
|
||||
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
|
||||
StringsManager.firstLaunch) ??
|
||||
true;
|
||||
final firstLaunch =
|
||||
await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
|
||||
if (firstLaunch) {
|
||||
storage.deleteAll();
|
||||
}
|
||||
await SharedPreferencesHelper.saveBoolToSP(
|
||||
StringsManager.firstLaunch, false);
|
||||
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
|
||||
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
||||
if (value.isEmpty) {
|
||||
return 'Token not found';
|
||||
@ -402,9 +394,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final String formattedTime = [
|
||||
if (days > 0) '${days}d', // Append 'd' for days
|
||||
if (days > 0 || hours > 0)
|
||||
hours
|
||||
.toString()
|
||||
.padLeft(2, '0'), // Show hours if there are days or hours
|
||||
hours.toString().padLeft(2, '0'), // Show hours if there are days or hours
|
||||
minutes.toString().padLeft(2, '0'),
|
||||
seconds.toString().padLeft(2, '0'),
|
||||
].join(':');
|
||||
@ -445,6 +435,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
static Future<void> logout(BuildContext context) async {
|
||||
final storage = FlutterSecureStorage();
|
||||
ProjectManager.clearProjectUUID();
|
||||
context.read<SpaceTreeBloc>().add(ClearAllData());
|
||||
storage.deleteAll();
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,19 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
// import 'package:graphview/GraphView.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
|
||||
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/services/home_api.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
|
||||
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
// final Graph graph = Graph()..isTree = true;
|
||||
@ -52,12 +51,12 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
|
||||
Future _fetchUserInfo(FetchUserInfo event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
user = await HomeApi().fetchUserInfo(uuid);
|
||||
|
||||
if (user != null && user!.project != null) {
|
||||
await ProjectManager.setProjectUUID(user!.project!.uuid);
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>().add(InitialEvent());
|
||||
}
|
||||
add(FetchTermEvent());
|
||||
add(FetchPolicyEvent());
|
||||
@ -93,12 +92,10 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future _confirmUserAgreement(
|
||||
ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||
Future _confirmUserAgreement(ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
policy = await HomeApi().confirmUserAgreements(uuid);
|
||||
emit(PolicyAgreement());
|
||||
} catch (e) {
|
||||
@ -122,6 +119,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.accessIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
context.go(RoutesConst.accessManagementPage);
|
||||
},
|
||||
color: null,
|
||||
@ -131,6 +129,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.spaseManagementIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
context.go(RoutesConst.spacesManagementPage);
|
||||
},
|
||||
color: ColorsManager.primaryColor,
|
||||
@ -140,6 +139,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
icon: Assets.devicesIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
BlocProvider.of<RoutineBloc>(context)
|
||||
.add(const TriggerSwitchTabsEvent(isRoutineTab: false));
|
||||
context.go(RoutesConst.deviceManagementPage);
|
||||
|
@ -219,6 +219,9 @@ class UserSpaceModel {
|
||||
final double x;
|
||||
final double y;
|
||||
final String icon;
|
||||
final String communityUuid;
|
||||
|
||||
//communityUuid
|
||||
|
||||
UserSpaceModel({
|
||||
required this.uuid,
|
||||
@ -231,22 +234,23 @@ class UserSpaceModel {
|
||||
required this.x,
|
||||
required this.y,
|
||||
required this.icon,
|
||||
required this.communityUuid,
|
||||
});
|
||||
|
||||
/// Create a [UserSpaceModel] from JSON data
|
||||
factory UserSpaceModel.fromJson(Map<String, dynamic> json) {
|
||||
return UserSpaceModel(
|
||||
uuid: json['uuid'] as String,
|
||||
createdAt: json['createdAt'] as String,
|
||||
updatedAt: json['updatedAt'] as String,
|
||||
spaceTuyaUuid: json['spaceTuyaUuid'] as String?,
|
||||
spaceName: json['spaceName'] as String,
|
||||
invitationCode: json['invitationCode'] as String?,
|
||||
disabled: json['disabled'] as bool,
|
||||
x: (json['x'] as num).toDouble(),
|
||||
y: (json['y'] as num).toDouble(),
|
||||
icon: json['icon'] as String,
|
||||
);
|
||||
uuid: json['uuid'] as String,
|
||||
createdAt: json['createdAt'] as String,
|
||||
updatedAt: json['updatedAt'] as String,
|
||||
spaceTuyaUuid: json['spaceTuyaUuid'] as String?,
|
||||
spaceName: json['spaceName'] as String,
|
||||
invitationCode: json['invitationCode'] as String?,
|
||||
disabled: json['disabled'] as bool,
|
||||
x: (json['x'] as num).toDouble(),
|
||||
y: (json['y'] as num).toDouble(),
|
||||
icon: json['icon'] as String,
|
||||
communityUuid: json['communityUuid'] as String);
|
||||
}
|
||||
|
||||
/// Convert the [UserSpaceModel] to JSON
|
||||
@ -262,6 +266,7 @@ class UserSpaceModel {
|
||||
'x': x,
|
||||
'y': y,
|
||||
'icon': icon,
|
||||
'communityUuid': communityUuid
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:bloc/bloc.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/common/custom_dialog.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/edit_user_model.dart';
|
||||
@ -8,14 +9,14 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialo
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/tree_node_model.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
|
||||
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||
import 'package:syncrow_web/services/user_permission.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
import 'package:syncrow_web/utils/navigation_service.dart';
|
||||
|
||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
UsersBloc() : super(UsersInitial()) {
|
||||
@ -65,8 +66,10 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
void isCompleteSpacesFun(
|
||||
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
isCompleteSpaces = selectedIds.isNotEmpty;
|
||||
var spaceBloc =
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||
|
||||
isCompleteSpaces = spaceBloc.state.selectedCommunities.isNotEmpty;
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
|
||||
@ -340,9 +343,11 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||
.where((id) => !communityIds.contains(id))
|
||||
.toList();
|
||||
// List<String> selectedIds =
|
||||
// getSelectedIds(updatedCommunities).where((id) => !communityIds.contains(id)).toList();
|
||||
|
||||
List<String> selectedSpacesId = getSelectedSpacesIds();
|
||||
// List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
|
||||
bool res = await UserPermissionApi().sendInviteUser(
|
||||
email: emailController.text,
|
||||
@ -351,7 +356,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
roleUuid: roleSelected,
|
||||
spaceUuids: selectedIds,
|
||||
spaceUuids: selectedSpacesId,
|
||||
projectUuid: projectUuid);
|
||||
|
||||
if (res) {
|
||||
@ -381,12 +386,20 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getSelectedSpacesIds() {
|
||||
List<String> selectedSpacesId = [];
|
||||
var spaceBloc =
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||
for (var community in spaceBloc.state.selectedCommunities) {
|
||||
selectedSpacesId
|
||||
.addAll(spaceBloc.state.selectedCommunityAndSpaces[community] ?? []);
|
||||
}
|
||||
return selectedSpacesId;
|
||||
}
|
||||
|
||||
_editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities)
|
||||
.where((id) => !communityIds.contains(id))
|
||||
.toList();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
bool res = await UserPermissionApi().editInviteUser(
|
||||
@ -396,7 +409,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
roleUuid: roleSelected,
|
||||
spaceUuids: selectedIds,
|
||||
spaceUuids: getSelectedSpacesIds(),
|
||||
projectUuid: projectUuid);
|
||||
if (res == true) {
|
||||
showCustomDialog(
|
||||
@ -502,6 +515,8 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
emit(UsersLoadingState());
|
||||
|
||||
try {
|
||||
var spaceBloc =
|
||||
NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
if (event.uuid?.isNotEmpty ?? false) {
|
||||
@ -516,13 +531,20 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
phoneController.text = res.phoneNumber ?? '';
|
||||
jobTitleController.text = res.jobTitle ?? '';
|
||||
res.roleType;
|
||||
if (updatedCommunities.isNotEmpty) {
|
||||
// Create a list of UUIDs to mark
|
||||
final uuidsToMark = res.spaces.map((space) => space.uuid).toList();
|
||||
// Print all IDs and mark nodes in updatedCommunities
|
||||
debugPrint('Printing and marking nodes in updatedCommunities:');
|
||||
_printAndMarkNodes(updatedCommunities, uuidsToMark);
|
||||
}
|
||||
res.spaces.map((space) {
|
||||
selectedIds.add(space.uuid);
|
||||
CommunityModel community = spaceBloc.state.communityList
|
||||
.firstWhere((item) => item.uuid == space.communityUuid);
|
||||
spaceBloc.add(OnSpaceSelected(community, space.uuid, []));
|
||||
}).toList();
|
||||
|
||||
// if (updatedCommunities.isNotEmpty) {
|
||||
// // Create a list of UUIDs to mark
|
||||
// final uuidsToMark = res.spaces.map((space) => space.uuid).toList();
|
||||
// // Print all IDs and mark nodes in updatedCommunities
|
||||
// debugPrint('Printing and marking nodes in updatedCommunities:');
|
||||
// _printAndMarkNodes(updatedCommunities, uuidsToMark);
|
||||
// }
|
||||
final roleId = roles
|
||||
.firstWhere((element) =>
|
||||
element.type ==
|
||||
@ -615,4 +637,16 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
emailController.dispose();
|
||||
firstNameController.dispose();
|
||||
lastNameController.dispose();
|
||||
emailController.dispose();
|
||||
phoneController.dispose();
|
||||
jobTitleController.dispose();
|
||||
roleSearchController.dispose();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
@ -25,7 +24,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (BuildContext context) => UsersBloc()
|
||||
..add(const LoadCommunityAndSpacesEvent())
|
||||
// ..add(const LoadCommunityAndSpacesEvent())
|
||||
..add(const RoleEvent()),
|
||||
child: BlocConsumer<UsersBloc, UsersState>(
|
||||
listener: (context, state) {},
|
||||
|
@ -26,13 +26,12 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (BuildContext context) => UsersBloc()
|
||||
..add(const LoadCommunityAndSpacesEvent())
|
||||
// ..add(const LoadCommunityAndSpacesEvent())
|
||||
..add(const RoleEvent())
|
||||
..add(GetUserByIdEvent(uuid: widget.userId)),
|
||||
child: BlocConsumer<UsersBloc, UsersState>(listener: (context, state) {
|
||||
if (state is SpacesLoadedState) {
|
||||
BlocProvider.of<UsersBloc>(context)
|
||||
.add(GetUserByIdEvent(uuid: widget.userId));
|
||||
BlocProvider.of<UsersBloc>(context).add(GetUserByIdEvent(uuid: widget.userId));
|
||||
}
|
||||
}, builder: (context, state) {
|
||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||
@ -40,8 +39,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
return Dialog(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||
width: 900,
|
||||
child: Column(
|
||||
children: [
|
||||
@ -70,8 +68,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
children: [
|
||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||
_buildStep3Indicator(
|
||||
3, "Role & Permissions", _blocRole),
|
||||
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -119,15 +116,13 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
if (currentStep < 3) {
|
||||
currentStep++;
|
||||
if (currentStep == 2) {
|
||||
_blocRole
|
||||
.add(CheckStepStatus(isEditUser: true));
|
||||
_blocRole.add(CheckStepStatus(isEditUser: true));
|
||||
} else if (currentStep == 3) {
|
||||
_blocRole.add(const CheckSpacesStepStatus());
|
||||
}
|
||||
} else {
|
||||
_blocRole.add(EditInviteUsers(
|
||||
context: context,
|
||||
userId: widget.userId!));
|
||||
_blocRole
|
||||
.add(EditInviteUsers(context: context, userId: widget.userId!));
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -136,8 +131,7 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
style: TextStyle(
|
||||
color: (_blocRole.isCompleteSpaces == false ||
|
||||
_blocRole.isCompleteBasics == false ||
|
||||
_blocRole.isCompleteRolePermissions ==
|
||||
false) &&
|
||||
_blocRole.isCompleteRolePermissions == false) &&
|
||||
currentStep == 3
|
||||
? ColorsManager.grayColor
|
||||
: ColorsManager.secondaryColor),
|
||||
@ -210,12 +204,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -273,12 +263,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
@ -335,12 +321,8 @@ class _EditUserDialogState extends State<EditUserDialog> {
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
color: currentStep == step
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -1,14 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class SpacesAccessView extends StatelessWidget {
|
||||
final String? userId;
|
||||
@ -27,10 +22,8 @@ class SpacesAccessView extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
'Spaces access',
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 20,
|
||||
color: Colors.black),
|
||||
style: context.textTheme.bodyLarge
|
||||
?.copyWith(fontWeight: FontWeight.w700, fontSize: 20, color: Colors.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 35,
|
||||
@ -42,77 +35,78 @@ class SpacesAccessView extends StatelessWidget {
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(20),
|
||||
topLeft: Radius.circular(20)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(20)),
|
||||
border: Border.all(
|
||||
color: ColorsManager.grayBorder)),
|
||||
child: TextFormField(
|
||||
style:
|
||||
const TextStyle(color: Colors.black),
|
||||
// controller: _blocRole.firstNameController,
|
||||
onChanged: (value) {
|
||||
_blocRole.add(SearchAnode(
|
||||
nodes: _blocRole.updatedCommunities,
|
||||
searchTerm: value));
|
||||
},
|
||||
decoration: textBoxDecoration(radios: 20)!
|
||||
.copyWith(
|
||||
fillColor: Colors.white,
|
||||
suffixIcon: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 16),
|
||||
child: SvgPicture.asset(
|
||||
Assets.textFieldSearch,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
hintStyle: context.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 7,
|
||||
child: Container(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: TreeView(userId: userId))))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(child: SpaceTreeView(onSelect: () {}))
|
||||
// Expanded(
|
||||
// child: SizedBox(
|
||||
// child: Column(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// flex: 2,
|
||||
// child: Container(
|
||||
// decoration: const BoxDecoration(
|
||||
// color: ColorsManager.circleRolesBackground,
|
||||
// borderRadius: BorderRadius.only(
|
||||
// topRight: Radius.circular(20),
|
||||
// topLeft: Radius.circular(20)),
|
||||
// ),
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Expanded(
|
||||
// child: Container(
|
||||
// decoration: BoxDecoration(
|
||||
// borderRadius: const BorderRadius.all(
|
||||
// Radius.circular(20)),
|
||||
// border: Border.all(
|
||||
// color: ColorsManager.grayBorder)),
|
||||
// child: TextFormField(
|
||||
// style:
|
||||
// const TextStyle(color: Colors.black),
|
||||
// // controller: _blocRole.firstNameController,
|
||||
// onChanged: (value) {
|
||||
// _blocRole.add(SearchAnode(
|
||||
// nodes: _blocRole.updatedCommunities,
|
||||
// searchTerm: value));
|
||||
// },
|
||||
// decoration: textBoxDecoration(radios: 20)!
|
||||
// .copyWith(
|
||||
// fillColor: Colors.white,
|
||||
// suffixIcon: Padding(
|
||||
// padding:
|
||||
// const EdgeInsets.only(right: 16),
|
||||
// child: SvgPicture.asset(
|
||||
// Assets.textFieldSearch,
|
||||
// width: 24,
|
||||
// height: 24,
|
||||
// ),
|
||||
// ),
|
||||
// hintStyle: context.textTheme.bodyMedium
|
||||
// ?.copyWith(
|
||||
// fontWeight: FontWeight.w400,
|
||||
// fontSize: 12,
|
||||
// color: ColorsManager.textGray),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// Expanded(
|
||||
// flex: 7,
|
||||
// child: Container(
|
||||
// color: ColorsManager.circleRolesBackground,
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: Container(
|
||||
// color: ColorsManager.whiteColors,
|
||||
// child: TreeView(userId: userId))))
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -13,6 +13,8 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/vi
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/de_activate_filter.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/name_filter.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/user_table.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
@ -25,8 +27,7 @@ class UsersPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
Widget actionButton(
|
||||
{bool isActive = false, required String title, Function()? onTap}) {
|
||||
Widget actionButton({bool isActive = false, required String title, Function()? onTap}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
@ -59,8 +60,7 @@ class UsersPage extends StatelessWidget {
|
||||
: ColorsManager.disabledPink.withOpacity(0.5),
|
||||
),
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
||||
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 5, top: 5),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@ -84,15 +84,12 @@ class UsersPage extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget changeIconStatus(
|
||||
{required String userId,
|
||||
required String status,
|
||||
required Function()? onTap}) {
|
||||
{required String userId, required String status, required Function()? onTap}) {
|
||||
return Center(
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
||||
padding: const EdgeInsets.only(left: 5, right: 5, bottom: 5, top: 5),
|
||||
child: SvgPicture.asset(
|
||||
status == "invited"
|
||||
? Assets.invitedIcon
|
||||
@ -160,6 +157,7 @@ class UsersPage extends StatelessWidget {
|
||||
const SizedBox(width: 20),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
@ -198,14 +196,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameAsc());
|
||||
context.read<UserTableBloc>().add(const SortUsersByNameAsc());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameDesc());
|
||||
context.read<UserTableBloc>().add(const SortUsersByNameDesc());
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -214,9 +208,8 @@ class UsersPage extends StatelessWidget {
|
||||
for (var item in _blocRole.jobTitle)
|
||||
item: _blocRole.selectedJobTitles.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
@ -256,9 +249,8 @@ class UsersPage extends StatelessWidget {
|
||||
for (var item in _blocRole.roleTypes)
|
||||
item: _blocRole.selectedRoles.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 4,
|
||||
@ -278,10 +270,9 @@ class UsersPage extends StatelessWidget {
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
Navigator.of(context).pop();
|
||||
context.read<UserTableBloc>().add(
|
||||
FilterUsersByRoleEvent(
|
||||
selectedRoles: selectedItems,
|
||||
sortOrder: _blocRole.currentSortRole));
|
||||
context.read<UserTableBloc>().add(FilterUsersByRoleEvent(
|
||||
selectedRoles: selectedItems,
|
||||
sortOrder: _blocRole.currentSortRole));
|
||||
},
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortRole = v;
|
||||
@ -296,14 +287,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateNewestToOldestEvent());
|
||||
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateOldestToNewestEvent());
|
||||
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -312,9 +299,8 @@ class UsersPage extends StatelessWidget {
|
||||
for (var item in _blocRole.createdBy)
|
||||
item: _blocRole.selectedCreatedBy.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 1,
|
||||
@ -352,9 +338,8 @@ class UsersPage extends StatelessWidget {
|
||||
item: _blocRole.selectedStatuses.contains(item),
|
||||
};
|
||||
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 0,
|
||||
@ -391,14 +376,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrderDate,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateNewestToOldestEvent());
|
||||
context.read<UserTableBloc>().add(const DateNewestToOldestEvent());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateOldestToNewestEvent());
|
||||
context.read<UserTableBloc>().add(const DateOldestToNewestEvent());
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -425,23 +406,17 @@ class UsersPage extends StatelessWidget {
|
||||
Text(user.createdTime ?? ''),
|
||||
Text(user.invitedBy),
|
||||
status(
|
||||
status: user.isEnabled == false
|
||||
? 'disabled'
|
||||
: user.status,
|
||||
status: user.isEnabled == false ? 'disabled' : user.status,
|
||||
),
|
||||
changeIconStatus(
|
||||
status: user.isEnabled == false
|
||||
? 'disabled'
|
||||
: user.status,
|
||||
status: user.isEnabled == false ? 'disabled' : user.status,
|
||||
userId: user.uuid,
|
||||
onTap: user.status != "invited"
|
||||
? () {
|
||||
context.read<UserTableBloc>().add(
|
||||
ChangeUserStatus(
|
||||
userId: user.uuid,
|
||||
newStatus: user.isEnabled == false
|
||||
? 'disabled'
|
||||
: user.status));
|
||||
context.read<UserTableBloc>().add(ChangeUserStatus(
|
||||
userId: user.uuid,
|
||||
newStatus:
|
||||
user.isEnabled == false ? 'disabled' : user.status));
|
||||
}
|
||||
: null,
|
||||
),
|
||||
@ -452,12 +427,12 @@ class UsersPage extends StatelessWidget {
|
||||
isActive: true,
|
||||
title: "Edit",
|
||||
onTap: () {
|
||||
context.read<SpaceTreeBloc>().add(ClearCachedData());
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return EditUserDialog(
|
||||
userId: user.uuid);
|
||||
return EditUserDialog(userId: user.uuid);
|
||||
},
|
||||
).then((v) {
|
||||
if (v != null) {
|
||||
@ -478,13 +453,10 @@ class UsersPage extends StatelessWidget {
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return DeleteUserDialog(
|
||||
onTapDelete: () async {
|
||||
return DeleteUserDialog(onTapDelete: () async {
|
||||
try {
|
||||
_blocRole.add(DeleteUserEvent(
|
||||
user.uuid, context));
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2));
|
||||
_blocRole.add(DeleteUserEvent(user.uuid, context));
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@ -514,20 +486,14 @@ class UsersPage extends StatelessWidget {
|
||||
visiblePagesCount: 4,
|
||||
buttonRadius: 10,
|
||||
selectedButtonColor: ColorsManager.secondaryColor,
|
||||
buttonUnSelectedBorderColor:
|
||||
ColorsManager.grayBorder,
|
||||
lastPageIcon:
|
||||
const Icon(Icons.keyboard_double_arrow_right),
|
||||
firstPageIcon:
|
||||
const Icon(Icons.keyboard_double_arrow_left),
|
||||
totalPages: (_blocRole.totalUsersCount.length /
|
||||
_blocRole.itemsPerPage)
|
||||
.ceil(),
|
||||
buttonUnSelectedBorderColor: ColorsManager.grayBorder,
|
||||
lastPageIcon: const Icon(Icons.keyboard_double_arrow_right),
|
||||
firstPageIcon: const Icon(Icons.keyboard_double_arrow_left),
|
||||
totalPages:
|
||||
(_blocRole.totalUsersCount.length / _blocRole.itemsPerPage).ceil(),
|
||||
currentPage: _blocRole.currentPage,
|
||||
onPageChanged: (int pageNumber) {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(ChangePage(pageNumber));
|
||||
context.read<UserTableBloc>().add(ChangePage(pageNumber));
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -7,7 +7,6 @@ import 'package:syncrow_web/pages/routines/widgets/main_routine_view/routine_vie
|
||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||
import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class RoutinesView extends StatefulWidget {
|
||||
const RoutinesView({super.key});
|
||||
|
@ -14,6 +14,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
on<OnCommunitySelected>(_onCommunitySelected);
|
||||
on<OnSpaceSelected>(_onSpaceSelected);
|
||||
on<SearchQueryEvent>(_onSearch);
|
||||
on<ClearAllData>(_clearAllData);
|
||||
on<ClearCachedData>(_clearCachedData);
|
||||
}
|
||||
|
||||
_fetchSpaces(InitialEvent event, Emitter<SpaceTreeState> emit) async {
|
||||
@ -89,6 +91,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
List<String> updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList());
|
||||
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||
List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityId] ?? [];
|
||||
|
||||
List<String> childrenIds = _getAllChildIds(event.children);
|
||||
|
||||
@ -96,14 +99,16 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
// Select the community and all its children
|
||||
updatedSelectedCommunities.add(event.communityId);
|
||||
updatedSelectedSpaces.addAll(childrenIds);
|
||||
selectedSpacesInCommunity.addAll(childrenIds);
|
||||
} else {
|
||||
// Unselect the community and all its children
|
||||
updatedSelectedCommunities.remove(event.communityId);
|
||||
updatedSelectedSpaces.removeWhere(childrenIds.contains);
|
||||
updatedSoldChecks.removeWhere(childrenIds.contains);
|
||||
selectedSpacesInCommunity.removeWhere(childrenIds.contains);
|
||||
}
|
||||
|
||||
communityAndSpaces[event.communityId] = updatedSelectedSpaces;
|
||||
communityAndSpaces[event.communityId] = selectedSpacesInCommunity;
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedCommunities: updatedSelectedCommunities,
|
||||
@ -123,6 +128,8 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
|
||||
Map<String, List<String>> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces);
|
||||
|
||||
List<String> selectedSpacesInCommunity = communityAndSpaces[event.communityModel.uuid] ?? [];
|
||||
|
||||
List<String> childrenIds = _getAllChildIds(event.children);
|
||||
bool isChildSelected = false;
|
||||
|
||||
@ -137,8 +144,11 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
// First click: Select the space and all its children
|
||||
updatedSelectedSpaces.add(event.spaceId);
|
||||
updatedSelectedCommunities.add(event.communityModel.uuid);
|
||||
selectedSpacesInCommunity.add(event.spaceId);
|
||||
|
||||
if (childrenIds.isNotEmpty) {
|
||||
updatedSelectedSpaces.addAll(childrenIds);
|
||||
selectedSpacesInCommunity.addAll(childrenIds);
|
||||
}
|
||||
|
||||
List<String> spaces = _getThePathToChild(event.communityModel.uuid, event.spaceId);
|
||||
@ -151,14 +161,17 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
childrenIds.isNotEmpty &&
|
||||
isChildSelected) {
|
||||
// Second click: Unselect space but keep children
|
||||
selectedSpacesInCommunity.remove(event.spaceId);
|
||||
updatedSelectedSpaces.remove(event.spaceId);
|
||||
updatedSoldChecks.add(event.spaceId);
|
||||
} else {
|
||||
// Third click: Unselect space and all its children
|
||||
selectedSpacesInCommunity.remove(event.spaceId);
|
||||
updatedSelectedSpaces.remove(event.spaceId);
|
||||
if (childrenIds.isNotEmpty) {
|
||||
updatedSelectedSpaces.removeWhere(childrenIds.contains);
|
||||
updatedSoldChecks.removeWhere(childrenIds.contains);
|
||||
selectedSpacesInCommunity.removeWhere(childrenIds.contains);
|
||||
}
|
||||
updatedSoldChecks.remove(event.spaceId);
|
||||
|
||||
@ -183,7 +196,7 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
}
|
||||
}
|
||||
|
||||
communityAndSpaces[event.communityModel.uuid] = updatedSelectedSpaces;
|
||||
communityAndSpaces[event.communityModel.uuid] = selectedSpacesInCommunity;
|
||||
|
||||
emit(state.copyWith(
|
||||
selectedCommunities: updatedSelectedCommunities.toSet().toList(),
|
||||
@ -241,6 +254,42 @@ class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
|
||||
}
|
||||
}
|
||||
|
||||
_clearAllData(ClearAllData event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
emit(state.copyWith(
|
||||
communitiesList: [],
|
||||
filteredCommunity: [],
|
||||
isSearching: false,
|
||||
soldCheck: [],
|
||||
selectedSpaces: [],
|
||||
selectedCommunities: [],
|
||||
selectedCommunityAndSpaces: {},
|
||||
searchQuery: '',
|
||||
expandedSpaces: [],
|
||||
expandedCommunity: []));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
_clearCachedData(ClearCachedData event, Emitter<SpaceTreeState> emit) async {
|
||||
try {
|
||||
emit(state.copyWith(
|
||||
communitiesList: state.communityList,
|
||||
filteredCommunity: [],
|
||||
isSearching: false,
|
||||
soldCheck: [],
|
||||
selectedSpaces: [],
|
||||
selectedCommunities: [],
|
||||
selectedCommunityAndSpaces: {},
|
||||
searchQuery: '',
|
||||
expandedSpaces: [],
|
||||
expandedCommunity: []));
|
||||
} catch (e) {
|
||||
emit(const SpaceTreeErrorState('Something went wrong'));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to determine if any space or its children match the search query
|
||||
bool _containsQuery(SpaceModel space, String query) {
|
||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
||||
|
@ -68,3 +68,7 @@ class SearchQueryEvent extends SpaceTreeEvent {
|
||||
@override
|
||||
List<Object> get props => [searchQuery];
|
||||
}
|
||||
|
||||
class ClearAllData extends SpaceTreeEvent {}
|
||||
|
||||
class ClearCachedData extends SpaceTreeEvent {}
|
||||
|
@ -4,9 +4,6 @@ import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_state.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
||||
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/temp_const.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
|
||||
class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
||||
final SpaceModelManagementApi api;
|
||||
@ -17,6 +14,7 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
||||
}) : super(SpaceModelLoaded(spaceModels: initialSpaceModels)) {
|
||||
on<CreateSpaceModel>(_onCreateSpaceModel);
|
||||
on<UpdateSpaceModel>(_onUpdateSpaceModel);
|
||||
on<DeleteSpaceModel>(_onDeleteSpaceModel);
|
||||
}
|
||||
|
||||
Future<void> _onCreateSpaceModel(
|
||||
@ -50,7 +48,7 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
final newSpaceModel =
|
||||
await api.getSpaceModel(event.spaceModelUuid ?? '', projectUuid);
|
||||
await api.getSpaceModel(event.spaceModelUuid, projectUuid);
|
||||
if (newSpaceModel != null) {
|
||||
final updatedSpaceModels = currentState.spaceModels.map((model) {
|
||||
return model.uuid == event.spaceModelUuid ? newSpaceModel : model;
|
||||
@ -62,4 +60,28 @@ class SpaceModelBloc extends Bloc<SpaceModelEvent, SpaceModelState> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onDeleteSpaceModel(
|
||||
DeleteSpaceModel event, Emitter<SpaceModelState> emit) async {
|
||||
final currentState = state;
|
||||
|
||||
if (currentState is SpaceModelLoaded) {
|
||||
try {
|
||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||
|
||||
final deletedSuccessfully =
|
||||
await api.deleteSpaceModel(event.spaceModelUuid, projectUuid);
|
||||
|
||||
if (deletedSuccessfully) {
|
||||
final updatedSpaceModels = currentState.spaceModels
|
||||
.where((model) => model.uuid != event.spaceModelUuid)
|
||||
.toList();
|
||||
|
||||
emit(SpaceModelLoaded(spaceModels: updatedSpaceModels));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SpaceModelError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,3 +34,12 @@ class UpdateSpaceModel extends SpaceModelEvent {
|
||||
@override
|
||||
List<Object?> get props => [spaceModelUuid];
|
||||
}
|
||||
|
||||
class DeleteSpaceModel extends SpaceModelEvent {
|
||||
final String spaceModelUuid;
|
||||
|
||||
DeleteSpaceModel({required this.spaceModelUuid});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [spaceModelUuid];
|
||||
}
|
||||
|
@ -90,7 +90,11 @@ class SpaceModelPage extends StatelessWidget {
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
child: SpaceModelCardWidget(model: model),
|
||||
child: SpaceModelCardWidget(
|
||||
model: model,
|
||||
pageContext: context,
|
||||
topActionsDisabled: false,
|
||||
),
|
||||
));
|
||||
},
|
||||
),
|
||||
|
@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DeleteSpaceModelDialog extends StatelessWidget {
|
||||
final VoidCallback onConfirmDelete;
|
||||
|
||||
const DeleteSpaceModelDialog({Key? key, required this.onConfirmDelete})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
return AlertDialog(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
title: Center(
|
||||
child: Text(
|
||||
"Delete Space Model",
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineLarge
|
||||
?.copyWith(color: ColorsManager.blackColor),
|
||||
),
|
||||
),
|
||||
content: SizedBox(
|
||||
width: screenWidth * 0.4,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Are you sure you want to delete?",
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"The existing sub-spaces, devices, and routines will remain associated with the spaces, but the connection will be removed.",
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: ColorsManager.lightGrayColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: CancelButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // Close dialog
|
||||
},
|
||||
label: "Cancel",
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: DefaultButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // Close dialog
|
||||
onConfirmDelete(); // Execute delete action
|
||||
},
|
||||
backgroundColor: ColorsManager.semiTransparentRed,
|
||||
borderRadius: 10,
|
||||
foregroundColor: ColorsManager.whiteColors,
|
||||
child: const Text('Delete'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -1,13 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/space_model_bloc.dart';
|
||||
|
||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/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/delete_space_model_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';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class SpaceModelCardWidget extends StatelessWidget {
|
||||
final SpaceTemplateModel model;
|
||||
final BuildContext? pageContext;
|
||||
final bool topActionsDisabled;
|
||||
|
||||
const SpaceModelCardWidget({Key? key, required this.model}) : super(key: key);
|
||||
const SpaceModelCardWidget({
|
||||
Key? key,
|
||||
required this.model,
|
||||
this.pageContext,
|
||||
this.topActionsDisabled = true,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -34,7 +51,7 @@ class SpaceModelCardWidget extends StatelessWidget {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
bool showOnlyName = constraints.maxWidth < 250;
|
||||
return Container(
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
@ -51,14 +68,50 @@ class SpaceModelCardWidget extends StatelessWidget {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
model.modelName,
|
||||
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
model.modelName,
|
||||
style:
|
||||
Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (!topActionsDisabled)
|
||||
GestureDetector(
|
||||
onTap: () => _showDeleteDialog(context),
|
||||
child: Container(
|
||||
width: 36, // Adjust size as needed
|
||||
height: 36,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.white,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.deleteSpaceModel, // Your actual SVG path
|
||||
width: 20,
|
||||
height: 20,
|
||||
colorFilter: const ColorFilter.mode(
|
||||
Colors.grey, BlendMode.srcIn),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!showOnlyName) ...[
|
||||
const SizedBox(height: 10),
|
||||
@ -117,4 +170,22 @@ class SpaceModelCardWidget extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showDeleteDialog(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (BuildContext dialogContext) {
|
||||
return DeleteSpaceModelDialog(
|
||||
onConfirmDelete: () {
|
||||
if (pageContext != null) {
|
||||
pageContext!.read<SpaceModelBloc>().add(
|
||||
DeleteSpaceModel(spaceModelUuid: model.uuid ?? ''),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -60,4 +60,17 @@ class SpaceModelManagementApi {
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<bool> deleteSpaceModel(String spaceModelUuid, String projectId) async {
|
||||
final response = await HTTPService().delete(
|
||||
path: ApiEndpoints.getSpaceModel
|
||||
.replaceAll('{projectId}', projectId)
|
||||
.replaceAll('{spaceModelUuid}', spaceModelUuid),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'] ?? false;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -71,4 +71,5 @@ abstract class ColorsManager {
|
||||
static const Color lightGrayBorderColor = Color(0xB2D5D5D5);
|
||||
//background: #F8F8F8;
|
||||
static const Color vividBlue = Color(0xFF023DFE);
|
||||
static const Color semiTransparentRed = Color(0x99FF0000);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ abstract class ApiEndpoints {
|
||||
|
||||
////// Devices Management ////////////////
|
||||
|
||||
static const String getAllDevices = '/projects/{projectId}/device';
|
||||
static const String getAllDevices = '/projects/{projectId}/devices';
|
||||
static const String getSpaceDevices =
|
||||
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
|
||||
static const String getDeviceStatus = '/device/{uuid}/functions/status';
|
||||
|
@ -258,6 +258,7 @@ class Assets {
|
||||
static const String doorSensor = 'assets/icons/door_sensor.svg';
|
||||
|
||||
static const String delete = 'assets/icons/delete.svg';
|
||||
static const String deleteSpaceModel = 'assets/icons/delete_space_model.svg';
|
||||
static const String edit = 'assets/icons/edit.svg';
|
||||
static const String editSpace = 'assets/icons/edit_space.svg';
|
||||
//assets/icons/routine/tab_to_run.svg
|
||||
|
Reference in New Issue
Block a user