petitspas/frontend/lib/widgets/admin/dashboard_admin.dart
2026-02-25 16:37:15 +01:00

318 lines
9.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:p_tits_pas/services/auth_service.dart';
/// Barre du dashboard admin : onglets Gestion des utilisateurs | Paramètres + déconnexion.
/// Pour le dashboard gestionnaire : [showSettingsTab] = false, [roleLabel] = 'Gestionnaire'.
class DashboardAppBarAdmin extends StatelessWidget
implements PreferredSizeWidget {
final int selectedIndex;
final ValueChanged<int> onTabChange;
final bool setupCompleted;
final bool showSettingsTab;
final String roleLabel;
const DashboardAppBarAdmin({
Key? key,
required this.selectedIndex,
required this.onTabChange,
this.setupCompleted = true,
this.showSettingsTab = true,
this.roleLabel = 'Admin',
}) : super(key: key);
@override
Size get preferredSize => const Size.fromHeight(kToolbarHeight + 10);
@override
Widget build(BuildContext context) {
return AppBar(
elevation: 0,
automaticallyImplyLeading: false,
title: Row(
children: [
const SizedBox(width: 24),
Image.asset(
'assets/images/logo.png',
height: 40,
fit: BoxFit.contain,
),
Expanded(
child: Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildNavItem(context, 'Gestion des utilisateurs', 0,
enabled: setupCompleted),
if (showSettingsTab) ...[
const SizedBox(width: 24),
_buildNavItem(context, 'Paramètres', 1, enabled: true),
],
],
),
),
),
],
),
actions: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Center(
child: Text(
roleLabel,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
),
),
Padding(
padding: const EdgeInsets.only(right: 16),
child: TextButton(
onPressed: () => _handleLogout(context),
style: TextButton.styleFrom(
backgroundColor: const Color(0xFF9CC5C0),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
child: const Text('Se déconnecter'),
),
),
],
);
}
Widget _buildNavItem(BuildContext context, String title, int index,
{bool enabled = true}) {
final bool isActive = index == selectedIndex;
return InkWell(
onTap: enabled ? () => onTabChange(index) : null,
child: Opacity(
opacity: enabled ? 1.0 : 0.5,
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,
),
),
),
),
);
}
void _handleLogout(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Déconnexion'),
content: const Text('Êtes-vous sûr de vouloir vous déconnecter ?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Annuler'),
),
ElevatedButton(
onPressed: () async {
Navigator.pop(context);
await AuthService.logout();
if (context.mounted) context.go('/login');
},
child: const Text('Déconnecter'),
),
],
),
);
}
}
/// Sous-barre : Gestionnaires | Parents | Assistantes maternelles | [Administrateurs].
/// [subTabCount] = 3 pour masquer l'onglet Administrateurs (dashboard gestionnaire).
class DashboardUserManagementSubBar extends StatelessWidget {
final int selectedSubIndex;
final ValueChanged<int> onSubTabChange;
final TextEditingController searchController;
final String searchHint;
final Widget? filterControl;
final VoidCallback? onAddPressed;
final String addLabel;
final int subTabCount;
static const List<String> _tabLabels = [
'Gestionnaires',
'Parents',
'Assistantes maternelles',
'Administrateurs',
];
const DashboardUserManagementSubBar({
Key? key,
required this.selectedSubIndex,
required this.onSubTabChange,
required this.searchController,
required this.searchHint,
this.filterControl,
this.onAddPressed,
this.addLabel = '+ Ajouter',
this.subTabCount = 4,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 56,
decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border(bottom: BorderSide(color: Colors.grey.shade300)),
),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 6),
child: Row(
children: [
for (int i = 0; i < subTabCount; i++) ...[
if (i > 0) const SizedBox(width: 12),
_buildSubNavItem(context, _tabLabels[i], i),
],
const SizedBox(width: 36),
_pillField(
width: 320,
child: TextField(
controller: searchController,
decoration: InputDecoration(
hintText: searchHint,
prefixIcon: const Icon(Icons.search, size: 18),
border: InputBorder.none,
isDense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
),
),
),
if (filterControl != null) ...[
const SizedBox(width: 12),
_pillField(width: 150, child: filterControl!),
],
const Spacer(),
_buildAddButton(),
],
),
);
}
Widget _pillField({required double width, required Widget child}) {
return Container(
width: width,
height: 34,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(18),
border: Border.all(color: Colors.black26),
),
alignment: Alignment.centerLeft,
child: child,
);
}
Widget _buildAddButton() {
return ElevatedButton.icon(
onPressed: onAddPressed,
icon: const Icon(Icons.add),
label: Text(addLabel),
);
}
Widget _buildSubNavItem(BuildContext context, String title, int index) {
final bool isActive = index == selectedSubIndex;
return InkWell(
onTap: () => onSubTabChange(index),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
color: isActive ? const Color(0xFF9CC5C0) : Colors.transparent,
borderRadius: BorderRadius.circular(16),
border: isActive ? null : Border.all(color: Colors.black26),
),
child: Text(
title,
style: TextStyle(
color: isActive ? Colors.white : Colors.black87,
fontWeight: isActive ? FontWeight.w600 : FontWeight.normal,
fontSize: 13,
),
),
),
);
}
}
/// Sous-barre Paramètres : Paramètres généraux | Paramètres territoriaux.
class DashboardSettingsSubBar extends StatelessWidget {
final int selectedSubIndex;
final ValueChanged<int> onSubTabChange;
const DashboardSettingsSubBar({
Key? key,
required this.selectedSubIndex,
required this.onSubTabChange,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
height: 48,
decoration: BoxDecoration(
color: Colors.grey.shade100,
border: Border(bottom: BorderSide(color: Colors.grey.shade300)),
),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 6),
child: Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildSubNavItem(context, 'Paramètres généraux', 0),
const SizedBox(width: 16),
_buildSubNavItem(context, 'Paramètres territoriaux', 1),
],
),
),
);
}
Widget _buildSubNavItem(BuildContext context, String title, int index) {
final bool isActive = index == selectedSubIndex;
return InkWell(
onTap: () => onSubTabChange(index),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 6),
decoration: BoxDecoration(
color: isActive ? const Color(0xFF9CC5C0) : Colors.transparent,
borderRadius: BorderRadius.circular(16),
border: isActive ? null : Border.all(color: Colors.black26),
),
child: Text(
title,
style: TextStyle(
color: isActive ? Colors.white : Colors.black87,
fontWeight: isActive ? FontWeight.w600 : FontWeight.normal,
fontSize: 13,
),
),
),
);
}
}