screen slide issue and add role
This commit is contained in:
parent
0102a7405c
commit
0d79d5a514
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
import '../../../../shared/models/permission_matrix_models.dart';
|
||||||
import '../../../../shared/models/user_management_models.dart';
|
import '../../../../shared/models/user_management_models.dart';
|
||||||
import '../../../roles/data/repositories/role_repository_impl.dart';
|
import '../../../roles/data/repositories/role_repository_impl.dart';
|
||||||
import '../../../roles/domain/usecases/role_usecases.dart';
|
import '../../../roles/domain/usecases/role_usecases.dart';
|
||||||
@ -8,28 +9,64 @@ import '../../../roles/presentation/providers/roles_provider.dart';
|
|||||||
class RoleFormState {
|
class RoleFormState {
|
||||||
const RoleFormState({
|
const RoleFormState({
|
||||||
this.editingRole,
|
this.editingRole,
|
||||||
|
this.permissionCatalog = const [],
|
||||||
this.isSubmitting = false,
|
this.isSubmitting = false,
|
||||||
this.errorMessage,
|
this.errorMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
final RoleCardModel? editingRole;
|
final RoleCardModel? editingRole;
|
||||||
|
final List<PermissionModuleCatalog> permissionCatalog;
|
||||||
final bool isSubmitting;
|
final bool isSubmitting;
|
||||||
final String? errorMessage;
|
final String? errorMessage;
|
||||||
|
|
||||||
|
/// Modules that expose a view permission in the live catalog.
|
||||||
|
List<PermissionModuleCatalog> get selectableModules => permissionCatalog
|
||||||
|
.where((module) => module.permissionIdForAction('view') != null)
|
||||||
|
.toList();
|
||||||
|
|
||||||
RoleFormState copyWith({
|
RoleFormState copyWith({
|
||||||
RoleCardModel? editingRole,
|
RoleCardModel? editingRole,
|
||||||
|
List<PermissionModuleCatalog>? permissionCatalog,
|
||||||
bool? isSubmitting,
|
bool? isSubmitting,
|
||||||
String? errorMessage,
|
String? errorMessage,
|
||||||
bool clearError = false,
|
bool clearError = false,
|
||||||
}) {
|
}) {
|
||||||
return RoleFormState(
|
return RoleFormState(
|
||||||
editingRole: editingRole ?? this.editingRole,
|
editingRole: editingRole ?? this.editingRole,
|
||||||
|
permissionCatalog: permissionCatalog ?? this.permissionCatalog,
|
||||||
isSubmitting: isSubmitting ?? this.isSubmitting,
|
isSubmitting: isSubmitting ?? this.isSubmitting,
|
||||||
errorMessage: clearError ? null : errorMessage ?? this.errorMessage,
|
errorMessage: clearError ? null : errorMessage ?? this.errorMessage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CreateRoleRequest buildCreateRoleRequest({
|
||||||
|
required String name,
|
||||||
|
required String description,
|
||||||
|
required Map<String, bool> selectedModules,
|
||||||
|
required List<PermissionModuleCatalog> catalog,
|
||||||
|
}) {
|
||||||
|
final viewModules = <String>[];
|
||||||
|
final permissionIds = <int>[];
|
||||||
|
|
||||||
|
for (final module in catalog) {
|
||||||
|
if (selectedModules[module.code] != true) continue;
|
||||||
|
|
||||||
|
final viewPermissionId = module.permissionIdForAction('view');
|
||||||
|
if (viewPermissionId == null) continue;
|
||||||
|
|
||||||
|
viewModules.add(module.code);
|
||||||
|
permissionIds.add(viewPermissionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateRoleRequest(
|
||||||
|
name: name,
|
||||||
|
description: description.isEmpty ? null : description,
|
||||||
|
permissionIds: permissionIds,
|
||||||
|
viewModules: viewModules,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final createRoleUseCaseProvider = Provider(
|
final createRoleUseCaseProvider = Provider(
|
||||||
(ref) => CreateRoleUseCase(ref.watch(roleRepositoryProvider)),
|
(ref) => CreateRoleUseCase(ref.watch(roleRepositoryProvider)),
|
||||||
);
|
);
|
||||||
@ -46,7 +83,13 @@ final roleFormProvider =
|
|||||||
class RoleFormNotifier extends FamilyAsyncNotifier<RoleFormState, String?> {
|
class RoleFormNotifier extends FamilyAsyncNotifier<RoleFormState, String?> {
|
||||||
@override
|
@override
|
||||||
Future<RoleFormState> build(String? roleId) async {
|
Future<RoleFormState> build(String? roleId) async {
|
||||||
if (roleId == null) return const RoleFormState();
|
if (roleId == null) {
|
||||||
|
final catalogResult = await ref.read(getPermissionCatalogUseCaseProvider)();
|
||||||
|
if (catalogResult.failure != null) throw catalogResult.failure!;
|
||||||
|
return RoleFormState(
|
||||||
|
permissionCatalog: catalogResult.data ?? const [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final cached = ref.read(rolesListProvider).valueOrNull?.roles;
|
final cached = ref.read(rolesListProvider).valueOrNull?.roles;
|
||||||
var editingRole = cached?.where((role) => role.id == roleId).firstOrNull;
|
var editingRole = cached?.where((role) => role.id == roleId).firstOrNull;
|
||||||
|
|||||||
@ -3,12 +3,12 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
|
|
||||||
import '../../../../core/errors/failure.dart';
|
import '../../../../core/errors/failure.dart';
|
||||||
import '../../../../core/utils/validators.dart';
|
import '../../../../core/utils/validators.dart';
|
||||||
|
import '../../../../shared/models/permission_matrix_models.dart';
|
||||||
import '../../../../shared/models/user_management_models.dart';
|
import '../../../../shared/models/user_management_models.dart';
|
||||||
import '../../../../shared/widgets/app_button.dart';
|
import '../../../../shared/widgets/app_button.dart';
|
||||||
import '../../../../shared/widgets/app_loading_view.dart';
|
import '../../../../shared/widgets/app_loading_view.dart';
|
||||||
import '../../../../shared/widgets/app_text_field.dart';
|
import '../../../../shared/widgets/app_text_field.dart';
|
||||||
import '../../../../shared/widgets/error_view.dart';
|
import '../../../../shared/widgets/error_view.dart';
|
||||||
import '../../domain/entities/rbac_entities.dart';
|
|
||||||
import '../providers/role_form_provider.dart';
|
import '../providers/role_form_provider.dart';
|
||||||
import 'rbac_widgets.dart';
|
import 'rbac_widgets.dart';
|
||||||
|
|
||||||
@ -27,10 +27,9 @@ class _RoleFormPanelState extends ConsumerState<RoleFormPanel> {
|
|||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
final _nameController = TextEditingController();
|
final _nameController = TextEditingController();
|
||||||
final _descriptionController = TextEditingController();
|
final _descriptionController = TextEditingController();
|
||||||
final Map<String, bool> _viewPermissions = {
|
final Map<String, bool> _viewPermissions = {};
|
||||||
for (final module in rbacModules) module.key: false,
|
|
||||||
};
|
|
||||||
bool _prefilled = false;
|
bool _prefilled = false;
|
||||||
|
bool _permissionsInitialized = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@ -49,6 +48,9 @@ class _RoleFormPanelState extends ConsumerState<RoleFormPanel> {
|
|||||||
Future<void> _save() async {
|
Future<void> _save() async {
|
||||||
if (!_formKey.currentState!.validate()) return;
|
if (!_formKey.currentState!.validate()) return;
|
||||||
|
|
||||||
|
final formState = ref.read(roleFormProvider(widget.roleId)).valueOrNull;
|
||||||
|
if (formState == null) return;
|
||||||
|
|
||||||
final notifier = ref.read(roleFormProvider(widget.roleId).notifier);
|
final notifier = ref.read(roleFormProvider(widget.roleId).notifier);
|
||||||
final bool success;
|
final bool success;
|
||||||
|
|
||||||
@ -62,9 +64,11 @@ class _RoleFormPanelState extends ConsumerState<RoleFormPanel> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
success = await notifier.submitCreate(
|
success = await notifier.submitCreate(
|
||||||
CreateRoleRequest(
|
buildCreateRoleRequest(
|
||||||
name: _nameController.text.trim(),
|
name: _nameController.text.trim(),
|
||||||
description: _descriptionController.text.trim(),
|
description: _descriptionController.text.trim(),
|
||||||
|
selectedModules: _viewPermissions,
|
||||||
|
catalog: formState.permissionCatalog,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -124,6 +128,20 @@ class _RoleFormPanelState extends ConsumerState<RoleFormPanel> {
|
|||||||
onRetry: () => ref.invalidate(roleFormProvider(widget.roleId)),
|
onRetry: () => ref.invalidate(roleFormProvider(widget.roleId)),
|
||||||
),
|
),
|
||||||
data: (formState) {
|
data: (formState) {
|
||||||
|
if (!widget.isEditing &&
|
||||||
|
!_permissionsInitialized &&
|
||||||
|
formState.selectableModules.isNotEmpty) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (!mounted || _permissionsInitialized) return;
|
||||||
|
setState(() {
|
||||||
|
_permissionsInitialized = true;
|
||||||
|
for (final module in formState.selectableModules) {
|
||||||
|
_viewPermissions.putIfAbsent(module.code, () => false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (formState.editingRole != null && !_prefilled) {
|
if (formState.editingRole != null && !_prefilled) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (!mounted || _prefilled) return;
|
if (!mounted || _prefilled) return;
|
||||||
@ -167,16 +185,27 @@ class _RoleFormPanelState extends ConsumerState<RoleFormPanel> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
...rbacModules.map((module) {
|
if (formState.selectableModules.isEmpty)
|
||||||
return ModulePermissionRow(
|
Text(
|
||||||
icon: module.icon,
|
'No view permissions available from the server.',
|
||||||
color: module.color,
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
label: module.label,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
value: _viewPermissions[module.key] ?? false,
|
),
|
||||||
onChanged: (v) =>
|
)
|
||||||
setState(() => _viewPermissions[module.key] = v),
|
else
|
||||||
);
|
...formState.selectableModules.asMap().entries.map((entry) {
|
||||||
}),
|
final module = entry.value;
|
||||||
|
final appearance =
|
||||||
|
permissionModuleAppearance(module.code, entry.key);
|
||||||
|
return ModulePermissionRow(
|
||||||
|
icon: appearance.icon,
|
||||||
|
color: appearance.color,
|
||||||
|
label: module.name,
|
||||||
|
value: _viewPermissions[module.code] ?? false,
|
||||||
|
onChanged: (v) =>
|
||||||
|
setState(() => _viewPermissions[module.code] = v),
|
||||||
|
);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -57,7 +57,8 @@ class RoleRemoteDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<RoleModel> createRole(CreateRoleRequest request) async {
|
Future<RoleModel> createRole(CreateRoleRequest request) async {
|
||||||
final response = await dio.post(ApiEndpoints.roles, data: request.toJson());
|
final payload = request.toJson()..removeWhere((_, value) => value == null);
|
||||||
|
final response = await dio.post(ApiEndpoints.roles, data: payload);
|
||||||
return _parseRole(response.data);
|
return _parseRole(response.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,13 @@ const permissionMatrixActionOrder = [
|
|||||||
'export',
|
'export',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
class ModulePermissionEntry {
|
||||||
|
const ModulePermissionEntry({required this.id, required this.action});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String action;
|
||||||
|
}
|
||||||
|
|
||||||
String permissionActionLabel(String action) => switch (action) {
|
String permissionActionLabel(String action) => switch (action) {
|
||||||
'view' => 'VIEW',
|
'view' => 'VIEW',
|
||||||
'create' => 'CREATE',
|
'create' => 'CREATE',
|
||||||
@ -32,25 +39,47 @@ class PermissionModuleCatalog {
|
|||||||
required this.code,
|
required this.code,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.actions,
|
required this.actions,
|
||||||
|
required this.permissions,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
final String code;
|
final String code;
|
||||||
final String name;
|
final String name;
|
||||||
final List<String> actions;
|
final List<String> actions;
|
||||||
|
final List<ModulePermissionEntry> permissions;
|
||||||
|
|
||||||
|
int? permissionIdForAction(String action) {
|
||||||
|
final normalized = action.toLowerCase();
|
||||||
|
for (final permission in permissions) {
|
||||||
|
if (permission.action.toLowerCase() == normalized) {
|
||||||
|
return int.tryParse(permission.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
factory PermissionModuleCatalog.fromJson(Map<String, dynamic> json) {
|
factory PermissionModuleCatalog.fromJson(Map<String, dynamic> json) {
|
||||||
final permissions = json['permissions'] as List<dynamic>? ?? const [];
|
final permissions = <ModulePermissionEntry>[];
|
||||||
final actions = permissions
|
for (final item in json['permissions'] as List<dynamic>? ?? const []) {
|
||||||
.map((item) => (item as Map<String, dynamic>)['action'] as String?)
|
if (item is! Map<String, dynamic>) continue;
|
||||||
.whereType<String>()
|
final action = item['action'] as String?;
|
||||||
.toList();
|
if (action == null) continue;
|
||||||
|
permissions.add(
|
||||||
|
ModulePermissionEntry(
|
||||||
|
id: item['id']?.toString() ?? '',
|
||||||
|
action: action,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final actions = permissions.map((entry) => entry.action).toList();
|
||||||
|
|
||||||
return PermissionModuleCatalog(
|
return PermissionModuleCatalog(
|
||||||
id: json['id']?.toString() ?? '',
|
id: json['id']?.toString() ?? '',
|
||||||
code: json['code'] as String? ?? '',
|
code: json['code'] as String? ?? '',
|
||||||
name: json['name'] as String? ?? '',
|
name: json['name'] as String? ?? '',
|
||||||
actions: sortPermissionActions(actions),
|
actions: sortPermissionActions(actions),
|
||||||
|
permissions: permissions,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,9 +211,9 @@ class RolePermissionMatrix {
|
|||||||
'ROLES' => styles[1],
|
'ROLES' => styles[1],
|
||||||
'MASTERS' => styles[2],
|
'MASTERS' => styles[2],
|
||||||
'VENDOR' => styles[3],
|
'VENDOR' => styles[3],
|
||||||
'PURCHASE_ORDERS' || 'PO' => styles[4],
|
'PURCHASE_ORDERS' || 'PURCHASE_ORDER' || 'PO' => styles[4],
|
||||||
'GRN' => styles[5],
|
'GRN' => styles[5],
|
||||||
'ASSETS' => styles[6],
|
'ASSETS' || 'ASSET' || 'ASSET_MANAGEMENT' => styles[6],
|
||||||
_ => styles[index % styles.length],
|
_ => styles[index % styles.length],
|
||||||
};
|
};
|
||||||
return byCode;
|
return byCode;
|
||||||
|
|||||||
@ -231,6 +231,8 @@ class CreateRoleRequest with _$CreateRoleRequest {
|
|||||||
required String name,
|
required String name,
|
||||||
String? description,
|
String? description,
|
||||||
@JsonKey(name: 'is_active') @Default(true) bool isActive,
|
@JsonKey(name: 'is_active') @Default(true) bool isActive,
|
||||||
|
@JsonKey(name: 'permission_ids') @Default([]) List<int> permissionIds,
|
||||||
|
@JsonKey(name: 'view_modules') @Default([]) List<String> viewModules,
|
||||||
}) = _CreateRoleRequest;
|
}) = _CreateRoleRequest;
|
||||||
|
|
||||||
factory CreateRoleRequest.fromJson(Map<String, dynamic> json) =>
|
factory CreateRoleRequest.fromJson(Map<String, dynamic> json) =>
|
||||||
|
|||||||
@ -3011,6 +3011,10 @@ mixin _$CreateRoleRequest {
|
|||||||
String? get description => throw _privateConstructorUsedError;
|
String? get description => throw _privateConstructorUsedError;
|
||||||
@JsonKey(name: 'is_active')
|
@JsonKey(name: 'is_active')
|
||||||
bool get isActive => throw _privateConstructorUsedError;
|
bool get isActive => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(name: 'permission_ids')
|
||||||
|
List<int> get permissionIds => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(name: 'view_modules')
|
||||||
|
List<String> get viewModules => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
/// Serializes this CreateRoleRequest to a JSON map.
|
/// Serializes this CreateRoleRequest to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@ -3033,6 +3037,8 @@ abstract class $CreateRoleRequestCopyWith<$Res> {
|
|||||||
String name,
|
String name,
|
||||||
String? description,
|
String? description,
|
||||||
@JsonKey(name: 'is_active') bool isActive,
|
@JsonKey(name: 'is_active') bool isActive,
|
||||||
|
@JsonKey(name: 'permission_ids') List<int> permissionIds,
|
||||||
|
@JsonKey(name: 'view_modules') List<String> viewModules,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3054,6 +3060,8 @@ class _$CreateRoleRequestCopyWithImpl<$Res, $Val extends CreateRoleRequest>
|
|||||||
Object? name = null,
|
Object? name = null,
|
||||||
Object? description = freezed,
|
Object? description = freezed,
|
||||||
Object? isActive = null,
|
Object? isActive = null,
|
||||||
|
Object? permissionIds = null,
|
||||||
|
Object? viewModules = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(
|
return _then(
|
||||||
_value.copyWith(
|
_value.copyWith(
|
||||||
@ -3069,6 +3077,14 @@ class _$CreateRoleRequestCopyWithImpl<$Res, $Val extends CreateRoleRequest>
|
|||||||
? _value.isActive
|
? _value.isActive
|
||||||
: isActive // ignore: cast_nullable_to_non_nullable
|
: isActive // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
|
permissionIds: null == permissionIds
|
||||||
|
? _value.permissionIds
|
||||||
|
: permissionIds // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<int>,
|
||||||
|
viewModules: null == viewModules
|
||||||
|
? _value.viewModules
|
||||||
|
: viewModules // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>,
|
||||||
)
|
)
|
||||||
as $Val,
|
as $Val,
|
||||||
);
|
);
|
||||||
@ -3088,6 +3104,8 @@ abstract class _$$CreateRoleRequestImplCopyWith<$Res>
|
|||||||
String name,
|
String name,
|
||||||
String? description,
|
String? description,
|
||||||
@JsonKey(name: 'is_active') bool isActive,
|
@JsonKey(name: 'is_active') bool isActive,
|
||||||
|
@JsonKey(name: 'permission_ids') List<int> permissionIds,
|
||||||
|
@JsonKey(name: 'view_modules') List<String> viewModules,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3108,6 +3126,8 @@ class __$$CreateRoleRequestImplCopyWithImpl<$Res>
|
|||||||
Object? name = null,
|
Object? name = null,
|
||||||
Object? description = freezed,
|
Object? description = freezed,
|
||||||
Object? isActive = null,
|
Object? isActive = null,
|
||||||
|
Object? permissionIds = null,
|
||||||
|
Object? viewModules = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(
|
return _then(
|
||||||
_$CreateRoleRequestImpl(
|
_$CreateRoleRequestImpl(
|
||||||
@ -3123,6 +3143,14 @@ class __$$CreateRoleRequestImplCopyWithImpl<$Res>
|
|||||||
? _value.isActive
|
? _value.isActive
|
||||||
: isActive // ignore: cast_nullable_to_non_nullable
|
: isActive // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
|
permissionIds: null == permissionIds
|
||||||
|
? _value._permissionIds
|
||||||
|
: permissionIds // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<int>,
|
||||||
|
viewModules: null == viewModules
|
||||||
|
? _value._viewModules
|
||||||
|
: viewModules // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -3135,7 +3163,10 @@ class _$CreateRoleRequestImpl implements _CreateRoleRequest {
|
|||||||
required this.name,
|
required this.name,
|
||||||
this.description,
|
this.description,
|
||||||
@JsonKey(name: 'is_active') this.isActive = true,
|
@JsonKey(name: 'is_active') this.isActive = true,
|
||||||
});
|
@JsonKey(name: 'permission_ids') final List<int> permissionIds = const [],
|
||||||
|
@JsonKey(name: 'view_modules') final List<String> viewModules = const [],
|
||||||
|
}) : _permissionIds = permissionIds,
|
||||||
|
_viewModules = viewModules;
|
||||||
|
|
||||||
factory _$CreateRoleRequestImpl.fromJson(Map<String, dynamic> json) =>
|
factory _$CreateRoleRequestImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$CreateRoleRequestImplFromJson(json);
|
_$$CreateRoleRequestImplFromJson(json);
|
||||||
@ -3147,10 +3178,27 @@ class _$CreateRoleRequestImpl implements _CreateRoleRequest {
|
|||||||
@override
|
@override
|
||||||
@JsonKey(name: 'is_active')
|
@JsonKey(name: 'is_active')
|
||||||
final bool isActive;
|
final bool isActive;
|
||||||
|
final List<int> _permissionIds;
|
||||||
|
@override
|
||||||
|
@JsonKey(name: 'permission_ids')
|
||||||
|
List<int> get permissionIds {
|
||||||
|
if (_permissionIds is EqualUnmodifiableListView) return _permissionIds;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_permissionIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> _viewModules;
|
||||||
|
@override
|
||||||
|
@JsonKey(name: 'view_modules')
|
||||||
|
List<String> get viewModules {
|
||||||
|
if (_viewModules is EqualUnmodifiableListView) return _viewModules;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(_viewModules);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'CreateRoleRequest(name: $name, description: $description, isActive: $isActive)';
|
return 'CreateRoleRequest(name: $name, description: $description, isActive: $isActive, permissionIds: $permissionIds, viewModules: $viewModules)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -3162,12 +3210,27 @@ class _$CreateRoleRequestImpl implements _CreateRoleRequest {
|
|||||||
(identical(other.description, description) ||
|
(identical(other.description, description) ||
|
||||||
other.description == description) &&
|
other.description == description) &&
|
||||||
(identical(other.isActive, isActive) ||
|
(identical(other.isActive, isActive) ||
|
||||||
other.isActive == isActive));
|
other.isActive == isActive) &&
|
||||||
|
const DeepCollectionEquality().equals(
|
||||||
|
other._permissionIds,
|
||||||
|
_permissionIds,
|
||||||
|
) &&
|
||||||
|
const DeepCollectionEquality().equals(
|
||||||
|
other._viewModules,
|
||||||
|
_viewModules,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, name, description, isActive);
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
isActive,
|
||||||
|
const DeepCollectionEquality().hash(_permissionIds),
|
||||||
|
const DeepCollectionEquality().hash(_viewModules),
|
||||||
|
);
|
||||||
|
|
||||||
/// Create a copy of CreateRoleRequest
|
/// Create a copy of CreateRoleRequest
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@ -3191,6 +3254,8 @@ abstract class _CreateRoleRequest implements CreateRoleRequest {
|
|||||||
required final String name,
|
required final String name,
|
||||||
final String? description,
|
final String? description,
|
||||||
@JsonKey(name: 'is_active') final bool isActive,
|
@JsonKey(name: 'is_active') final bool isActive,
|
||||||
|
@JsonKey(name: 'permission_ids') final List<int> permissionIds,
|
||||||
|
@JsonKey(name: 'view_modules') final List<String> viewModules,
|
||||||
}) = _$CreateRoleRequestImpl;
|
}) = _$CreateRoleRequestImpl;
|
||||||
|
|
||||||
factory _CreateRoleRequest.fromJson(Map<String, dynamic> json) =
|
factory _CreateRoleRequest.fromJson(Map<String, dynamic> json) =
|
||||||
@ -3203,6 +3268,12 @@ abstract class _CreateRoleRequest implements CreateRoleRequest {
|
|||||||
@override
|
@override
|
||||||
@JsonKey(name: 'is_active')
|
@JsonKey(name: 'is_active')
|
||||||
bool get isActive;
|
bool get isActive;
|
||||||
|
@override
|
||||||
|
@JsonKey(name: 'permission_ids')
|
||||||
|
List<int> get permissionIds;
|
||||||
|
@override
|
||||||
|
@JsonKey(name: 'view_modules')
|
||||||
|
List<String> get viewModules;
|
||||||
|
|
||||||
/// Create a copy of CreateRoleRequest
|
/// Create a copy of CreateRoleRequest
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
|||||||
@ -228,6 +228,16 @@ _$CreateRoleRequestImpl _$$CreateRoleRequestImplFromJson(
|
|||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
description: json['description'] as String?,
|
description: json['description'] as String?,
|
||||||
isActive: json['is_active'] as bool? ?? true,
|
isActive: json['is_active'] as bool? ?? true,
|
||||||
|
permissionIds:
|
||||||
|
(json['permission_ids'] as List<dynamic>?)
|
||||||
|
?.map((e) => (e as num).toInt())
|
||||||
|
.toList() ??
|
||||||
|
const [],
|
||||||
|
viewModules:
|
||||||
|
(json['view_modules'] as List<dynamic>?)
|
||||||
|
?.map((e) => e as String)
|
||||||
|
.toList() ??
|
||||||
|
const [],
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$$CreateRoleRequestImplToJson(
|
Map<String, dynamic> _$$CreateRoleRequestImplToJson(
|
||||||
@ -236,6 +246,8 @@ Map<String, dynamic> _$$CreateRoleRequestImplToJson(
|
|||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'description': instance.description,
|
'description': instance.description,
|
||||||
'is_active': instance.isActive,
|
'is_active': instance.isActive,
|
||||||
|
'permission_ids': instance.permissionIds,
|
||||||
|
'view_modules': instance.viewModules,
|
||||||
};
|
};
|
||||||
|
|
||||||
_$UpdateRoleRequestImpl _$$UpdateRoleRequestImplFromJson(
|
_$UpdateRoleRequestImpl _$$UpdateRoleRequestImplFromJson(
|
||||||
|
|||||||
@ -118,11 +118,13 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.dashboard,
|
path: RouteConstants.dashboard,
|
||||||
builder: (context, state) => const DashboardScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const DashboardScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.companies,
|
path: RouteConstants.companies,
|
||||||
builder: (context, state) => const CompanyListScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const CompanyListScreen()),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'add',
|
path: 'add',
|
||||||
@ -137,7 +139,8 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.branches,
|
path: RouteConstants.branches,
|
||||||
builder: (context, state) => const BranchListScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const BranchListScreen()),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'add',
|
path: 'add',
|
||||||
@ -152,14 +155,18 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.usersRoleManagement,
|
path: RouteConstants.usersRoleManagement,
|
||||||
builder: (context, state) => UsersRoleManagementScreen(
|
pageBuilder: (context, state) => shellPage(
|
||||||
initialTab: rbacTabFromLocation(state.uri.toString()),
|
state,
|
||||||
|
UsersRoleManagementScreen(
|
||||||
|
initialTab: rbacTabFromLocation(state.uri.toString()),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.users,
|
path: RouteConstants.users,
|
||||||
builder: (context, state) => const UsersRoleManagementScreen(
|
pageBuilder: (context, state) => shellPage(
|
||||||
initialTab: RbacTab.users,
|
state,
|
||||||
|
const UsersRoleManagementScreen(initialTab: RbacTab.users),
|
||||||
),
|
),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
@ -180,8 +187,9 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.roles,
|
path: RouteConstants.roles,
|
||||||
builder: (context, state) => const UsersRoleManagementScreen(
|
pageBuilder: (context, state) => shellPage(
|
||||||
initialTab: RbacTab.roles,
|
state,
|
||||||
|
const UsersRoleManagementScreen(initialTab: RbacTab.roles),
|
||||||
),
|
),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
@ -194,11 +202,13 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.profile,
|
path: RouteConstants.profile,
|
||||||
builder: (context, state) => const UserProfileScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const UserProfileScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.assets,
|
path: RouteConstants.assets,
|
||||||
builder: (context, state) => const AssetListScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const AssetListScreen()),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'add',
|
path: 'add',
|
||||||
@ -242,27 +252,33 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.departments,
|
path: RouteConstants.departments,
|
||||||
builder: (context, state) => const DepartmentsScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const DepartmentsScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.locations,
|
path: RouteConstants.locations,
|
||||||
builder: (context, state) => const LocationsScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const LocationsScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.uom,
|
path: RouteConstants.uom,
|
||||||
builder: (context, state) => const UomScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const UomScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.reports,
|
path: RouteConstants.reports,
|
||||||
builder: (context, state) => const ReportsScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const ReportsScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.auditLogs,
|
path: RouteConstants.auditLogs,
|
||||||
builder: (context, state) => const AuditLogsScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const AuditLogsScreen()),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.settings,
|
path: RouteConstants.settings,
|
||||||
builder: (context, state) => const SettingsScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const SettingsScreen()),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: 'general',
|
path: 'general',
|
||||||
@ -301,7 +317,8 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
if (DevConfig.screenPreviewEnabled)
|
if (DevConfig.screenPreviewEnabled)
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: RouteConstants.screenGallery,
|
path: RouteConstants.screenGallery,
|
||||||
builder: (context, state) => const ScreenGalleryScreen(),
|
pageBuilder: (context, state) =>
|
||||||
|
shellPage(state, const ScreenGalleryScreen()),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -319,6 +336,15 @@ Widget _themedRoute(GoRouterState state, Widget child) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instant swap for main shell pages — prevents old page showing through
|
||||||
|
/// during sidebar navigation slide transitions.
|
||||||
|
Page<void> shellPage(GoRouterState state, Widget child) {
|
||||||
|
return NoTransitionPage<void>(
|
||||||
|
key: state.pageKey,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
class _AuthListenable extends ChangeNotifier {
|
class _AuthListenable extends ChangeNotifier {
|
||||||
_AuthListenable(this._ref) {
|
_AuthListenable(this._ref) {
|
||||||
_ref.listen(authStateProvider, (_, __) => notifyListeners());
|
_ref.listen(authStateProvider, (_, __) => notifyListeners());
|
||||||
|
|||||||
@ -30,6 +30,20 @@ class _AppShellState extends ConsumerState<AppShell> {
|
|||||||
final _scaffoldKey = GlobalKey<ScaffoldState>();
|
final _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
bool _sidebarCollapsed = false;
|
bool _sidebarCollapsed = false;
|
||||||
|
|
||||||
|
Widget _pageContent(BuildContext context, String currentRoute, Widget child) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
child: Material(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
surfaceTintColor: Colors.transparent,
|
||||||
|
child: ThemeKeyedSubtree(
|
||||||
|
pageKey: currentRoute,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final authState = ref.watch(authStateProvider);
|
final authState = ref.watch(authStateProvider);
|
||||||
@ -71,10 +85,7 @@ class _AppShellState extends ConsumerState<AppShell> {
|
|||||||
_scaffoldKey.currentState?.closeDrawer();
|
_scaffoldKey.currentState?.closeDrawer();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
body: ThemeKeyedSubtree(
|
body: _pageContent(context, currentRoute, widget.child),
|
||||||
pageKey: currentRoute,
|
|
||||||
child: widget.child,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,10 +108,7 @@ class _AppShellState extends ConsumerState<AppShell> {
|
|||||||
onItemTap: (route) => goAndDismissOverlays(context, route),
|
onItemTap: (route) => goAndDismissOverlays(context, route),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ThemeKeyedSubtree(
|
child: _pageContent(context, currentRoute, widget.child),
|
||||||
pageKey: currentRoute,
|
|
||||||
child: widget.child,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -126,10 +134,7 @@ class _AppShellState extends ConsumerState<AppShell> {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ThemeKeyedSubtree(
|
child: _pageContent(context, currentRoute, widget.child),
|
||||||
pageKey: currentRoute,
|
|
||||||
child: widget.child,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user