Skip to content

Commit 6861139

Browse files
committed
feat: Añadir widgets de permisos: PermissionWidget, PermissionFloatingActionButton, PermissionActionButton, PermissionPopupMenuButton y PermissionPopupMenuItem
1 parent 360d398 commit 6861139

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:boilerplate_frontend_mobile_flutter/app/services/permission_service.dart';
3+
4+
/// Widget que condiciona la visualización de su hijo basado en permisos
5+
class PermissionWidget extends StatelessWidget {
6+
final List<String> requiredPermissions;
7+
final Widget child;
8+
final Widget? fallback;
9+
final bool requireAll; // Si es true, requiere TODOS los permisos, si es false, requiere AL MENOS UNO
10+
11+
const PermissionWidget({
12+
super.key,
13+
required this.requiredPermissions,
14+
required this.child,
15+
this.fallback,
16+
this.requireAll = false,
17+
});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
final permissionService = PermissionService.instance;
22+
bool hasPermission;
23+
24+
if (requireAll) {
25+
hasPermission = permissionService.hasAllPermissions(requiredPermissions);
26+
} else {
27+
hasPermission = permissionService.hasAnyPermission(requiredPermissions);
28+
}
29+
30+
if (hasPermission) {
31+
return child;
32+
} else {
33+
return fallback ?? const SizedBox.shrink();
34+
}
35+
}
36+
}
37+
38+
/// Widget que oculta el FloatingActionButton si no tiene permisos de creación
39+
class PermissionFloatingActionButton extends StatelessWidget {
40+
final String module; // ej: 'users', 'roles', etc.
41+
final VoidCallback onPressed;
42+
final Widget? child;
43+
final String? tooltip;
44+
45+
const PermissionFloatingActionButton({
46+
super.key,
47+
required this.module,
48+
required this.onPressed,
49+
this.child,
50+
this.tooltip,
51+
});
52+
53+
@override
54+
Widget build(BuildContext context) {
55+
return PermissionWidget(
56+
requiredPermissions: ['$module:create'],
57+
child: FloatingActionButton(
58+
onPressed: onPressed,
59+
tooltip: tooltip,
60+
child: child ?? const Icon(Icons.add),
61+
),
62+
);
63+
}
64+
}
65+
66+
/// Widget que condiciona botones de acción (editar, eliminar, etc.)
67+
class PermissionActionButton extends StatelessWidget {
68+
final String action; // 'edit', 'delete', 'show', etc.
69+
final String module; // 'users', 'roles', etc.
70+
final VoidCallback onPressed;
71+
final Widget child;
72+
73+
const PermissionActionButton({
74+
super.key,
75+
required this.action,
76+
required this.module,
77+
required this.onPressed,
78+
required this.child,
79+
});
80+
81+
@override
82+
Widget build(BuildContext context) {
83+
return PermissionWidget(
84+
requiredPermissions: ['$module:$action'],
85+
child: child,
86+
);
87+
}
88+
}
89+
90+
/// PopupMenuButton que filtra opciones basado en permisos
91+
class PermissionPopupMenuButton<T> extends StatelessWidget {
92+
final String module;
93+
final Function(T) onSelected;
94+
final Widget? icon;
95+
final List<PermissionPopupMenuItem<T>> items;
96+
97+
const PermissionPopupMenuButton({
98+
super.key,
99+
required this.module,
100+
required this.onSelected,
101+
required this.items,
102+
this.icon,
103+
});
104+
105+
@override
106+
Widget build(BuildContext context) {
107+
final permissionService = PermissionService.instance;
108+
109+
// Filtrar elementos basado en permisos
110+
final filteredItems = items.where((item) {
111+
if (item.requiredPermissions.isEmpty) return true;
112+
return permissionService.hasAnyPermission(item.requiredPermissions);
113+
}).map((item) => PopupMenuItem<T>(
114+
value: item.value,
115+
child: item.child,
116+
)).toList();
117+
118+
// Si no hay elementos después del filtrado, no mostrar el botón
119+
if (filteredItems.isEmpty) {
120+
return const SizedBox.shrink();
121+
}
122+
123+
return PopupMenuButton<T>(
124+
icon: icon,
125+
onSelected: onSelected,
126+
itemBuilder: (context) => filteredItems,
127+
);
128+
}
129+
}
130+
131+
/// Elemento de PopupMenu con permisos
132+
class PermissionPopupMenuItem<T> {
133+
final T value;
134+
final Widget child;
135+
final List<String> requiredPermissions;
136+
137+
const PermissionPopupMenuItem({
138+
required this.value,
139+
required this.child,
140+
this.requiredPermissions = const [],
141+
});
142+
}
143+
144+
/// Mixin para facilitar la verificación de permisos en las vistas
145+
mixin PermissionMixin {
146+
PermissionService get permissionService => PermissionService.instance;
147+
148+
bool hasPermission(String permission) => permissionService.hasPermission(permission);
149+
bool hasAnyPermission(List<String> permissions) => permissionService.hasAnyPermission(permissions);
150+
bool hasAllPermissions(List<String> permissions) => permissionService.hasAllPermissions(permissions);
151+
152+
bool canAccess(String module) => permissionService.canAccessView(module);
153+
bool canCreate(String module) => permissionService.canCreate(module);
154+
bool canEdit(String module) => permissionService.canEdit(module);
155+
bool canDelete(String module) => permissionService.canDelete(module);
156+
bool canShow(String module) => permissionService.canShow(module);
157+
158+
Map<String, bool> getCrudPermissions(String module) => permissionService.getCrudPermissions(module);
159+
}

0 commit comments

Comments
 (0)