Compare commits
No commits in common. "d4d8d5f5c6693d029034f1f1db6ac36e1aba6e74" and "70033dd9c3c496ae7d6a43be82f2ba71aafe8bfa" have entirely different histories.
d4d8d5f5c6
...
70033dd9c3
@ -1,7 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/DashboardSidebarAdmin.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/Statistique_manage_widget.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/admin_manage_widget.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/assistante_maternelle_management_widget.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/gestionnaire_management_widget.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/parent_managmant_widget.dart';
|
||||
@ -27,58 +24,41 @@ class _AdminDashboardScreenState extends State<AdminDashboardScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(60.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
),
|
||||
child: DashboardAppBarAdmin(
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChange: onTabChange,
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(60.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(color: Colors.grey.shade300),
|
||||
),
|
||||
),
|
||||
child: DashboardAppBarAdmin(
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChange: onTabChange,
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 250,
|
||||
child: DashboardSidebarAdmin(
|
||||
selectedIndex: selectedIndex,
|
||||
onTabChange: onTabChange,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _getBody(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const AppFooter(),
|
||||
],
|
||||
),
|
||||
);
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _getBody(),
|
||||
),
|
||||
const AppFooter(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _getBody() {
|
||||
switch (selectedIndex) {
|
||||
case 0:
|
||||
return const GestionnaireManagementWidget();
|
||||
return const GestionnaireManagementWidget();
|
||||
case 1:
|
||||
return const ParentManagementWidget();
|
||||
case 2:
|
||||
return const AssistanteMaternelleManagementWidget();
|
||||
case 3:
|
||||
return const AdministrateurManagementWidget();
|
||||
case 4:
|
||||
return const StatistiqueManageWidget();
|
||||
return const Center(child: Text("👨💼 Administrateurs"));
|
||||
default:
|
||||
return const Center(child: Text("Page non trouvée"));
|
||||
}
|
||||
|
||||
@ -112,51 +112,40 @@ class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getUserId() async {
|
||||
final token = await TokenService.getToken();
|
||||
if (token == null) return '';
|
||||
/*static const String _usersKey = 'users';
|
||||
static const String _parentsKey = 'parents';
|
||||
static const String _childrenKey = 'children';
|
||||
|
||||
try {
|
||||
final parts = token.split('.');
|
||||
if (parts.length != 3) return '';
|
||||
|
||||
final payload = parts[1];
|
||||
final normalizedPayload = base64Url.normalize(payload);
|
||||
final decoded = utf8.decode(base64Url.decode(normalizedPayload));
|
||||
final Map<String, dynamic> payloadMap = jsonDecode(decoded);
|
||||
|
||||
return payloadMap['sub'] ?? '';
|
||||
} catch (e) {
|
||||
print('Error extracting user id from token: $e');
|
||||
return '';
|
||||
}
|
||||
// Méthode pour se connecter (mode démonstration)
|
||||
static Future<AppUser> login(String email, String password) async {
|
||||
await Future.delayed(const Duration(seconds: 1)); // Simule un délai de traitement
|
||||
throw Exception('Mode démonstration - Connexion désactivée');
|
||||
}
|
||||
|
||||
Future<String?> getUserNameById() async {
|
||||
final userid = await getUserId();
|
||||
final token = await TokenService.getToken();
|
||||
|
||||
if (token == null || userid.isEmpty) return null;
|
||||
try {
|
||||
final response = await http.get(
|
||||
Uri.parse('$baseUrl${ApiConfig.users}/$userid'),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'accept': '*/*',
|
||||
},
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
final firstName = data['prenom'];
|
||||
// final lastName = data['nom'];
|
||||
return '$firstName';
|
||||
} else {
|
||||
print('Erreur Api: ${response.statusCode} - ${response.body}');
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error fetching user name: $e');
|
||||
return null;
|
||||
}
|
||||
// Méthode pour s'inscrire (mode démonstration)
|
||||
static Future<AppUser> register({
|
||||
required String email,
|
||||
required String password,
|
||||
required String firstName,
|
||||
required String lastName,
|
||||
required String role,
|
||||
}) async {
|
||||
await Future.delayed(const Duration(seconds: 1)); // Simule un délai de traitement
|
||||
throw Exception('Mode démonstration - Inscription désactivée');
|
||||
}
|
||||
|
||||
// Méthode pour se déconnecter (mode démonstration)
|
||||
static Future<void> logout() async {
|
||||
// Ne fait rien en mode démonstration
|
||||
}
|
||||
|
||||
// Méthode pour vérifier si l'utilisateur est connecté (mode démonstration)
|
||||
static Future<bool> isLoggedIn() async {
|
||||
return false; // Toujours non connecté en mode démonstration
|
||||
}
|
||||
|
||||
// Méthode pour récupérer l'utilisateur connecté (mode démonstration)
|
||||
static Future<AppUser?> getCurrentUser() async {
|
||||
return null; // Aucun utilisateur en mode démonstration
|
||||
}*/
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DashboardSidebarAdmin extends StatelessWidget {
|
||||
final int selectedIndex;
|
||||
final ValueChanged<int> onTabChange;
|
||||
|
||||
const DashboardSidebarAdmin({
|
||||
Key? key,
|
||||
required this.selectedIndex,
|
||||
required this.onTabChange,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final items = [
|
||||
{'title': 'Gestionnaires', 'icon': Icons.admin_panel_settings},
|
||||
{'title': 'Parents', 'icon': Icons.family_restroom},
|
||||
{'title': 'Assistantes maternelles', 'icon': Icons.woman},
|
||||
{'title': 'Administrateurs', 'icon': Icons.supervisor_account},
|
||||
{'title': 'Statistiques', 'icon': Icons.bar_chart},
|
||||
];
|
||||
|
||||
return Container(
|
||||
width: 250,
|
||||
color: const Color(0xFFF7F7F7),
|
||||
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Avatar en haut
|
||||
Center(
|
||||
child: Column(
|
||||
children: const [
|
||||
CircleAvatar(radius: 32, child: Icon(Icons.person, size: 32)),
|
||||
SizedBox(height: 8),
|
||||
Text("Admin", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
const Text("Navigation", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Navigation
|
||||
...List.generate(items.length, (index) {
|
||||
final item = items[index];
|
||||
final isActive = index == selectedIndex;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: ListTile(
|
||||
tileColor: isActive ? const Color(0xFF9CC5C0) : null,
|
||||
leading: Icon(item['icon'] as IconData, color: isActive ? Color(0xFF9CC5C0) : Colors.black54),
|
||||
title: Text(
|
||||
item['title'] as String,
|
||||
style: TextStyle(
|
||||
color: isActive ? Color(0xFF9CC5C0) : Colors.black,
|
||||
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
onTap: () => onTabChange(index),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StatistiqueManageWidget extends StatelessWidget {
|
||||
const StatistiqueManageWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Statistiques',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,132 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/base_user_management.dart';
|
||||
|
||||
class AdministrateurManagementWidget extends StatelessWidget {
|
||||
const AdministrateurManagementWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BaseUserManagementWidget(
|
||||
config: UserDisplayConfig(
|
||||
title: 'Administrateur',
|
||||
role: 'administrateur',
|
||||
defaultIcon: Icons.admin_panel_settings,
|
||||
filterFields: [
|
||||
FilterField(
|
||||
label: 'Rechercher',
|
||||
hint: 'Nom ou email',
|
||||
type: FilterType.text,
|
||||
filter: (user, query) {
|
||||
final fullName =
|
||||
'${user['firstName'] ?? ''} ${user['lastName'] ?? ''}'
|
||||
.toLowerCase();
|
||||
final email = (user['email'] ?? '').toLowerCase();
|
||||
return fullName.contains(query.toLowerCase()) ||
|
||||
email.contains(query.toLowerCase());
|
||||
},
|
||||
),
|
||||
FilterField(
|
||||
label: 'Statut',
|
||||
hint: 'Tous',
|
||||
type: FilterType.dropdown,
|
||||
options: ['actif', 'en_attente', 'inactif', 'supprimé'],
|
||||
filter: (user, status) {
|
||||
if (status.isEmpty) return true;
|
||||
return user['statut']?.toString().toLowerCase() ==
|
||||
status.toLowerCase();
|
||||
},
|
||||
),
|
||||
],
|
||||
actions: [
|
||||
const UserAction(
|
||||
icon: Icons.edit,
|
||||
color: Colors.orange,
|
||||
tooltip: 'Modifier',
|
||||
onPressed: _editAdministrateur,
|
||||
),
|
||||
const UserAction(
|
||||
icon: Icons.security,
|
||||
color: Colors.blue,
|
||||
tooltip: 'Gérer droits',
|
||||
onPressed: _manageRights,
|
||||
),
|
||||
const UserAction(
|
||||
icon: Icons.lock_reset,
|
||||
color: Colors.purple,
|
||||
tooltip: 'Réinitialiser MDP',
|
||||
onPressed: _resetPassword,
|
||||
),
|
||||
const UserAction(
|
||||
icon: Icons.toggle_on,
|
||||
color: Colors.green,
|
||||
tooltip: 'Activer/Désactiver',
|
||||
onPressed: _toggleStatus,
|
||||
),
|
||||
const UserAction(
|
||||
icon: Icons.delete,
|
||||
color: Colors.red,
|
||||
tooltip: 'Supprimer',
|
||||
onPressed: _deleteAdministrateur,
|
||||
),
|
||||
],
|
||||
getDisplayName: (user) => '${user['prenom'] ?? ''} ${user['nom'] ?? ''}',
|
||||
getSubtitle: (user) {
|
||||
final email = user['email'] ?? '';
|
||||
final profession = user['profession'] ?? 'Non spécifiée';
|
||||
final ville = user['ville'] ?? '';
|
||||
// final statut = AdministrateurService.getStatutDisplay(user['statut']);
|
||||
final statut = user['statut'] ?? 'inactif';
|
||||
final changementMdp =
|
||||
user['changement_mdp_obligatoire'] == true ? 'MDP à changer' : '';
|
||||
|
||||
return '$email\n$profession${ville.isNotEmpty ? ' • $ville' : ''}\nStatut: $statut ${changementMdp.isNotEmpty ? '• $changementMdp' : ''}';
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
static Future<void> _editAdministrateur(
|
||||
BuildContext context, Map<String, dynamic> user) async {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'Modifier administrateur: ${user['prenom']} ${user['nom']}')),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _manageRights(
|
||||
BuildContext context, Map<String, dynamic> user) async {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Gérer droits pour: ${user['prenom']} ${user['nom']}')),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _resetPassword(
|
||||
BuildContext context, Map<String, dynamic> user) async {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'Réinitialiser mot de passe pour: ${user['prenom']} ${user['nom']}')),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _toggleStatus(
|
||||
BuildContext context, Map<String, dynamic> user) async {
|
||||
final currentStatus = user['statut'] ?? 'inactif';
|
||||
final newStatus = currentStatus == 'actif' ? 'inactif' : 'actif';
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'${newStatus == 'actif' ? 'Activer' : 'Désactiver'} administrateur: ${user['prenom']} ${user['nom']}')),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> _deleteAdministrateur(
|
||||
BuildContext context, Map<String, dynamic> user) async {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'Supprimer administrateur: ${user['prenom']} ${user['nom']}')),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -47,7 +47,7 @@ class AssistanteMaternelleManagementWidget extends StatelessWidget {
|
||||
label: 'Statut',
|
||||
hint: 'Tous',
|
||||
type: FilterType.dropdown,
|
||||
options: ['actif', 'en_attente', 'inactif'],
|
||||
options: ['actif', 'en attente', 'inactif'],
|
||||
filter: (user, status) {
|
||||
if (status.isEmpty) return true;
|
||||
return user['statut']?.toString().toLowerCase() == status.toLowerCase();
|
||||
@ -55,19 +55,19 @@ class AssistanteMaternelleManagementWidget extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
actions: [
|
||||
const UserAction(
|
||||
UserAction(
|
||||
icon: Icons.edit,
|
||||
color: Colors.orange,
|
||||
tooltip: 'Modifier',
|
||||
onPressed: _editAssistante,
|
||||
),
|
||||
const UserAction(
|
||||
UserAction(
|
||||
icon: Icons.delete,
|
||||
color: Colors.red,
|
||||
tooltip: 'Supprimer',
|
||||
onPressed: _deleteAssistante,
|
||||
),
|
||||
const UserAction(
|
||||
UserAction(
|
||||
icon: Icons.location_on,
|
||||
color: Colors.green,
|
||||
tooltip: 'Voir zone',
|
||||
|
||||
@ -140,7 +140,7 @@ class _BaseUserManagementWidgetState extends State<BaseUserManagementWidget> {
|
||||
switch (status.toString().toLowerCase()) {
|
||||
case 'actif':
|
||||
return 'Actif';
|
||||
case 'en_attente':
|
||||
case 'en attente':
|
||||
return 'En attente';
|
||||
case 'inactif':
|
||||
return 'Inactif';
|
||||
@ -156,7 +156,7 @@ class _BaseUserManagementWidgetState extends State<BaseUserManagementWidget> {
|
||||
switch (status) {
|
||||
case 'actif':
|
||||
return Colors.green;
|
||||
case 'en_attente':
|
||||
case 'en attente':
|
||||
return Colors.orange;
|
||||
case 'inactif':
|
||||
return Colors.grey;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/services/auth_service.dart';
|
||||
|
||||
class DashboardAppBarAdmin extends StatelessWidget implements PreferredSizeWidget {
|
||||
final int selectedIndex;
|
||||
@ -7,29 +6,6 @@ class DashboardAppBarAdmin extends StatelessWidget implements PreferredSizeWidge
|
||||
|
||||
const DashboardAppBarAdmin({Key? key, required this.selectedIndex, required this.onTabChange}) : super(key: key);
|
||||
|
||||
void _Logout(BuildContext context) async {
|
||||
try {
|
||||
final authS = AuthService();
|
||||
await authS.logout();
|
||||
Navigator.of(context).pushReplacementNamed('/login');
|
||||
} catch (e) {
|
||||
print('Erreur lors de la déconnexion: $e');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Erreur lors de la déconnexion'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _getUserName() async {
|
||||
final authS = AuthService();
|
||||
final userName = await authS.getUserNameById();
|
||||
return userName ?? 'Admin';
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight + 10);
|
||||
|
||||
@ -53,36 +29,33 @@ class DashboardAppBarAdmin extends StatelessWidget implements PreferredSizeWidge
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.1),
|
||||
|
||||
// Navigation principale
|
||||
// _buildNavItem(context, 'Gestionnaires', 0),
|
||||
// const SizedBox(width: 24),
|
||||
// _buildNavItem(context, 'Parents', 1),
|
||||
// const SizedBox(width: 24),
|
||||
// _buildNavItem(context, 'Assistantes maternelles', 2),
|
||||
// const SizedBox(width: 24),
|
||||
// _buildNavItem(context, 'Administrateurs', 4),
|
||||
_buildNavItem(context, 'Gestionnaires', 0),
|
||||
const SizedBox(width: 24),
|
||||
_buildNavItem(context, 'Parents', 1),
|
||||
const SizedBox(width: 24),
|
||||
_buildNavItem(context, 'Assistantes maternelles', 2),
|
||||
const SizedBox(width: 24),
|
||||
_buildNavItem(context, 'Administrateurs', 3),
|
||||
],
|
||||
),
|
||||
actions: isMobile
|
||||
? [_buildMobileMenu(context)]
|
||||
: [
|
||||
// Nom de l'utilisateur
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Center(
|
||||
child: FutureBuilder<String>(
|
||||
future: _getUserName(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Text("Chargement...");
|
||||
} else if (snapshot.hasError) {
|
||||
return const Text("Erreur");
|
||||
} else {
|
||||
return Text(snapshot.data ?? "Admin");
|
||||
}
|
||||
}
|
||||
child: Text(
|
||||
'Admin',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Bouton déconnexion
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
@ -104,28 +77,28 @@ class DashboardAppBarAdmin extends StatelessWidget implements PreferredSizeWidge
|
||||
);
|
||||
}
|
||||
|
||||
// Widget _buildNavItem(BuildContext context, String title, int index) {
|
||||
// final bool isActive = index == selectedIndex;
|
||||
// return InkWell(
|
||||
// onTap: () => onTabChange(index),
|
||||
// child: Container(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
// decoration: BoxDecoration(
|
||||
// color: isActive ? const Color(0xFF9CC5C0) : Colors.transparent,
|
||||
// borderRadius: BorderRadius.circular(20),
|
||||
// border: isActive ? null : Border.all(color: Colors.black26),
|
||||
// ),
|
||||
// child: Text(
|
||||
// title,
|
||||
// style: TextStyle(
|
||||
// color: isActive ? Colors.white : Colors.black,
|
||||
// fontWeight: isActive ? FontWeight.w600 : FontWeight.normal,
|
||||
// fontSize: 14,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
Widget _buildNavItem(BuildContext context, String title, int index) {
|
||||
final bool isActive = index == selectedIndex;
|
||||
return InkWell(
|
||||
onTap: () => onTabChange(index),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: isActive ? const Color(0xFF9CC5C0) : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: isActive ? null : Border.all(color: Colors.black26),
|
||||
),
|
||||
child: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: isActive ? Colors.white : Colors.black,
|
||||
fontWeight: isActive ? FontWeight.w600 : FontWeight.normal,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Widget _buildMobileMenu(BuildContext context) {
|
||||
@ -160,8 +133,8 @@ class DashboardAppBarAdmin extends StatelessWidget implements PreferredSizeWidge
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Navigator.pop(context);
|
||||
_Logout(context);
|
||||
Navigator.pop(context);
|
||||
// TODO: Implémenter la logique de déconnexion
|
||||
},
|
||||
child: const Text('Déconnecter'),
|
||||
),
|
||||
|
||||
@ -1,98 +1,118 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/services/user_service.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/base_user_management.dart';
|
||||
|
||||
class ParentManagementWidget extends StatelessWidget {
|
||||
class ParentManagementWidget extends StatefulWidget {
|
||||
const ParentManagementWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BaseUserManagementWidget(
|
||||
config: UserDisplayConfig(
|
||||
title: 'Gestion des Parents',
|
||||
role: 'parent',
|
||||
defaultIcon: Icons.person_outline,
|
||||
filterFields: [
|
||||
FilterField(
|
||||
label: 'Rechercher',
|
||||
hint: 'Nom ou email',
|
||||
type: FilterType.text,
|
||||
filter: (user, query) {
|
||||
final fullName = '${user['prenom'] ?? ''} ${user['nom'] ?? ''}'.toLowerCase();
|
||||
final email = (user['email'] ?? '').toLowerCase();
|
||||
return fullName.contains(query.toLowerCase()) ||
|
||||
email.contains(query.toLowerCase());
|
||||
},
|
||||
),
|
||||
FilterField(
|
||||
label: 'Statut',
|
||||
hint: 'Tous',
|
||||
type: FilterType.dropdown,
|
||||
options: ['actif', 'en_attente', 'inactif', 'supprimé'],
|
||||
filter: (user, status) {
|
||||
if (status.isEmpty) return true;
|
||||
return user['statut']?.toString().toLowerCase() == status.toLowerCase();
|
||||
},
|
||||
),
|
||||
FilterField(
|
||||
label: 'Nombre d\'enfants',
|
||||
hint: 'Minimum',
|
||||
type: FilterType.number,
|
||||
filter: (user, query) {
|
||||
final nombreEnfants = int.tryParse(user['nombreEnfants']?.toString() ?? '0') ?? 0;
|
||||
final minEnfants = int.tryParse(query) ?? 0;
|
||||
return nombreEnfants >= minEnfants;
|
||||
},
|
||||
),
|
||||
],
|
||||
actions: [
|
||||
const UserAction(
|
||||
icon: Icons.edit,
|
||||
color: Colors.orange,
|
||||
tooltip: 'Modifier',
|
||||
onPressed: _editParent,
|
||||
),
|
||||
const UserAction(
|
||||
icon: Icons.delete,
|
||||
color: Colors.red,
|
||||
tooltip: 'Supprimer',
|
||||
onPressed: _deleteParent,
|
||||
),
|
||||
const UserAction(
|
||||
icon: Icons.child_care,
|
||||
color: Colors.purple,
|
||||
tooltip: 'Voir enfants',
|
||||
onPressed: _showChildren,
|
||||
),
|
||||
],
|
||||
getDisplayName: (user) => '${user['prenom'] ?? ''} ${user['nom'] ?? ''}',
|
||||
getSubtitle: (user) {
|
||||
final email = user['email'] ?? '';
|
||||
final nombreEnfants = user['nombreEnfants'] ?? user['children']?.length ?? 0;
|
||||
return '$email\nNombre d\'enfants: $nombreEnfants';
|
||||
},
|
||||
),
|
||||
);
|
||||
State<ParentManagementWidget> createState() => _ParentManagementWidgetState();
|
||||
}
|
||||
|
||||
class _ParentManagementWidgetState extends State<ParentManagementWidget> {
|
||||
|
||||
final UserService _userService = UserService();
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
|
||||
List<Map<String, dynamic>> _allParents = [];
|
||||
List<Map<String, dynamic>> _filteredParents = [];
|
||||
String? _selectedStatus;
|
||||
bool _isLoading = true;
|
||||
String? _error;
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadParents();
|
||||
}
|
||||
|
||||
static Future<void> _editParent(BuildContext context, Map<String, dynamic> parent) async {
|
||||
// TODO: Implémenter l'édition
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Fonctionnalité de modification à implémenter'),
|
||||
backgroundColor: Colors.orange,
|
||||
),
|
||||
);
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
static Future<void> _deleteParent(BuildContext context, Map<String, dynamic> parent) async {
|
||||
Future <void> _loadParents() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_error = null;
|
||||
});
|
||||
|
||||
try {
|
||||
final parents = await _userService.getUsersByRole("parent");
|
||||
setState(() {
|
||||
_allParents = parents;
|
||||
_filteredParents = parents;
|
||||
_isLoading = false;
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_error = e.toString();
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _applyFilters() {
|
||||
setState(() {
|
||||
_filteredParents = _allParents.where((parent) {
|
||||
final searchQuery = _searchController.text.toLowerCase();
|
||||
final fullName = '${parent['prenom'] ?? ''} ${parent['nom'] ?? ''}'.toLowerCase();
|
||||
final email = (parent['email'] ?? '').toLowerCase();
|
||||
|
||||
bool matchesSearch = searchQuery.isEmpty ||
|
||||
fullName.contains(searchQuery) ||
|
||||
email.contains(searchQuery);
|
||||
|
||||
bool matchesStatus = _selectedStatus == null ||
|
||||
_selectedStatus!.isEmpty ||
|
||||
parent['statut']?.toString() == _selectedStatus;
|
||||
|
||||
return matchesSearch && matchesStatus;
|
||||
}).toList();
|
||||
});
|
||||
}
|
||||
|
||||
String _getStatusDisplay(Map<String, dynamic> parent) {
|
||||
final status = parent['statut'];
|
||||
if (status == null) return 'Non défini';
|
||||
switch (status.toString().toLowerCase()) {
|
||||
case 'actif':
|
||||
return 'Actif';
|
||||
case 'en_attente':
|
||||
return 'En attente';
|
||||
case 'inactif':
|
||||
return 'Inactif';
|
||||
case 'supprimé':
|
||||
return 'Supprimé';
|
||||
default:
|
||||
return status.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Color _getStatusColor(Map<String, dynamic> parent) {
|
||||
final status = parent['statut']?.toString().toLowerCase();
|
||||
switch (status) {
|
||||
case 'actif':
|
||||
return Colors.green;
|
||||
case 'en_attente':
|
||||
return Colors.orange;
|
||||
case 'inactif':
|
||||
return Colors.grey;
|
||||
case 'supprimé':
|
||||
return Colors.red;
|
||||
default:
|
||||
return Colors.grey;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _confirmDelete(Map<String, dynamic> parent) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Confirmer la suppression'),
|
||||
content: Text(
|
||||
'Êtes-vous sûr de vouloir supprimer le compte de ${parent['prenom']} ${parent['nom']} ?\n\n'
|
||||
'Cette action supprimera également tous les contrats et données associés.'
|
||||
'Êtes-vous sûr de vouloir supprimer le compte de ${parent['firstName']} ${parent['lastName']} ?'
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
@ -109,87 +129,276 @@ class ParentManagementWidget extends StatelessWidget {
|
||||
);
|
||||
|
||||
if (confirmed == true) {
|
||||
try {
|
||||
final userService = UserService();
|
||||
final success = await userService.deleteUser(parent['id']);
|
||||
|
||||
if (success && context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('${parent['prenom']} ${parent['nom']} supprimé avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
throw Exception('Erreur lors de la suppression');
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur: ${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
await _deleteParent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _showChildren(BuildContext context, Map<String, dynamic> parent) async {
|
||||
final children = parent['children'] as List<dynamic>? ?? [];
|
||||
Future<void> _deleteParent(Map<String, dynamic> parent) async {
|
||||
try {
|
||||
final success = await _userService.deleteUser(parent['id']);
|
||||
if (success) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('${parent['firstName']} ${parent['lastName']} supprimé avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
_loadParents(); // Recharger la liste
|
||||
} else {
|
||||
throw Exception('Erreur lors de la suppression');
|
||||
}
|
||||
} catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur: ${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _viewParentDetails(Map<String, dynamic> parent) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('Enfants de ${parent['prenom']} ${parent['nom']}'),
|
||||
content: Container(
|
||||
width: double.maxFinite,
|
||||
constraints: const BoxConstraints(maxHeight: 400),
|
||||
child: children.isEmpty
|
||||
? const Text('Aucun enfant enregistré')
|
||||
: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: children.map((child) => Card(
|
||||
child: ListTile(
|
||||
leading: const Icon(Icons.child_care),
|
||||
title: Text(child['prenom'] ?? child['firstName'] ?? 'Nom non défini'),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (child['dateNaissance'] != null || child['birthDate'] != null)
|
||||
Text('Né(e) le: ${child['dateNaissance'] ?? child['birthDate']}'),
|
||||
if (child['age'] != null)
|
||||
Text('Âge: ${child['age']} ans'),
|
||||
],
|
||||
),
|
||||
isThreeLine: true,
|
||||
),
|
||||
)).toList(),
|
||||
),
|
||||
),
|
||||
title: Text('${parent['firstName']} ${parent['lastName']}'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Email: ${parent['email']}'),
|
||||
Text('Rôle: ${parent['role']}'),
|
||||
Text('Statut: ${_getStatusDisplay(parent)}'),
|
||||
Text('ID: ${parent['id']}'),
|
||||
if (parent['createdAt'] != null)
|
||||
Text('Créé le: ${DateTime.parse(parent['createdAt']).toLocal().toString().split(' ')[0]}'),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Fermer'),
|
||||
),
|
||||
if (children.isNotEmpty)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
// TODO: Naviguer vers la gestion des enfants
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Navigation vers la gestion des enfants à implémenter'),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('Gérer les enfants'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Gestion des Parents (${_filteredParents.length})',
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: _loadParents,
|
||||
tooltip: 'Actualiser',
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildSearchSection(),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: _buildParentsList(),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildSearchSection() {
|
||||
return Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 250,
|
||||
child: TextField(
|
||||
controller: _searchController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Rechercher un parent",
|
||||
hintText: "Nom ou email",
|
||||
border: OutlineInputBorder(),
|
||||
prefixIcon: Icon(Icons.search),
|
||||
),
|
||||
onChanged: (value) => _applyFilters(),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 200,
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: _selectedStatus,
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Statut",
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
items: const [
|
||||
DropdownMenuItem(value: null, child: Text("Tous")),
|
||||
DropdownMenuItem(value: "active", child: Text("Actif")),
|
||||
DropdownMenuItem(value: "pending", child: Text("En attente")),
|
||||
DropdownMenuItem(value: "inactive", child: Text("Inactif")),
|
||||
DropdownMenuItem(value: "deleted", child: Text("Supprimé")),
|
||||
],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_selectedStatus = value;
|
||||
});
|
||||
_applyFilters();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildParentsList() {
|
||||
if (_isLoading) {
|
||||
return const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(),
|
||||
SizedBox(height: 16),
|
||||
Text('Chargement des parents...'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (_error != null) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.error_outline, size: 48, color: Colors.red[300]),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Erreur de chargement',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
_error!,
|
||||
textAlign: TextAlign.center,
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
onPressed: _loadParents,
|
||||
child: const Text('Réessayer'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (_filteredParents.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(Icons.people_outline, size: 48, color: Colors.grey[400]),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
_allParents.isEmpty ? 'Aucun parent trouvé' : 'Aucun résultat',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
if (_allParents.isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
const Text('Essayez de modifier vos critères de recherche'),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: _filteredParents.length,
|
||||
itemBuilder: (context, index) {
|
||||
final parent = _filteredParents[index];
|
||||
return Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: _getStatusColor(parent).withOpacity(0.2),
|
||||
child: Text(
|
||||
'${parent['firstName']?[0] ?? ''}${parent['lastName']?[0] ?? ''}',
|
||||
style: TextStyle(
|
||||
color: _getStatusColor(parent),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text('${parent['firstName'] ?? ''} ${parent['lastName'] ?? ''}'),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(parent['email'] ?? ''),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatusColor(parent).withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: _getStatusColor(parent)),
|
||||
),
|
||||
child: Text(
|
||||
_getStatusDisplay(parent),
|
||||
style: TextStyle(
|
||||
color: _getStatusColor(parent),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
isThreeLine: true,
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.visibility, color: Colors.blue),
|
||||
tooltip: "Voir détails",
|
||||
onPressed: () => _viewParentDetails(parent),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit, color: Colors.orange),
|
||||
tooltip: "Modifier",
|
||||
onPressed: () {
|
||||
// TODO: Implémenter la modification
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Fonctionnalité de modification à implémenter'),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete, color: Colors.red),
|
||||
tooltip: "Supprimer",
|
||||
onPressed: () => _confirmDelete(parent),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/services/auth_service.dart';
|
||||
|
||||
class DashboardAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final int selectedIndex;
|
||||
@ -10,29 +9,6 @@ class DashboardAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
@override
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight + 10);
|
||||
|
||||
Future <String> _getUserName() async {
|
||||
final authS = AuthService();
|
||||
final userName = await authS.getUserNameById();
|
||||
return userName ?? 'Bienvenue';
|
||||
}
|
||||
|
||||
void _logout (BuildContext context) {
|
||||
try {
|
||||
final authS = AuthService();
|
||||
authS.logout();
|
||||
Navigator.of(context).pushReplacementNamed('/login');
|
||||
} catch (e) {
|
||||
print('Erreur lors de la déconnexion: $e');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Erreur lors de la déconnexion'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isMobile = MediaQuery.of(context).size.width < 768;
|
||||
@ -41,6 +17,20 @@ class DashboardAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
elevation: 0,
|
||||
title: Row(
|
||||
children: [
|
||||
// Logo de la ville
|
||||
// Container(
|
||||
// height: 32,
|
||||
// width: 32,
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.white,
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// ),
|
||||
// child: const Icon(
|
||||
// Icons.location_city,
|
||||
// color: Color(0xFF9CC5C0),
|
||||
// size: 20,
|
||||
// ),
|
||||
// ),
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.19),
|
||||
const Text(
|
||||
"P'tit Pas",
|
||||
@ -64,20 +54,16 @@ class DashboardAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
? [_buildMobileMenu(context)]
|
||||
: [
|
||||
// Nom de l'utilisateur
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16),
|
||||
child: Center(
|
||||
child: FutureBuilder<String>(
|
||||
future: _getUserName(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Text("Chargement...");
|
||||
} else if (snapshot.hasError) {
|
||||
return const Text("Erreur");
|
||||
} else {
|
||||
return Text(snapshot.data ?? "Admin");
|
||||
}
|
||||
}
|
||||
child: Text(
|
||||
'Jean Dupont',
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -159,7 +145,6 @@ class DashboardAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
_logout(context);
|
||||
// TODO: Implémenter la logique de déconnexion
|
||||
},
|
||||
child: const Text('Déconnecter'),
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/widgets/dashbord_parent/ChildrenSidebarwidget.dart';
|
||||
import 'package:p_tits_pas/widgets/dashbord_parent/children_sidebar.dart';
|
||||
import 'package:p_tits_pas/widgets/dashbord_parent/wid_mainContentArea.dart';
|
||||
import 'package:p_tits_pas/widgets/messaging_sidebar.dart';
|
||||
|
||||
Widget Dashbord_body() {
|
||||
return Row(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user