barcode_scanner/lib/components/drawer_component.dart
mandreshope 40ef71a28b refactor: Standardizes data model naming convention
Renames `AuthStruct` to `AuthModel` and `ProductStruct` to `ProductModel` to align with a consistent data model naming convention.

Updates all relevant imports, type declarations, and method signatures across the application to reflect these changes, improving codebase clarity and maintainability.

Includes minor code style improvements and refactorings in other components.
2025-07-29 10:09:03 +03:00

303 lines
9.6 KiB
Dart

import 'package:barcode_scanner/backend/schema/user/user_struct.dart';
import 'package:barcode_scanner/pages/login/login_page_model.dart';
import 'package:barcode_scanner/pages/operation/reception/reception_page_model.dart';
import 'package:barcode_scanner/router/go_router_builder.dart';
import 'package:barcode_scanner/router/go_secure_router_builder.dart';
import 'package:barcode_scanner/themes/app_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class DrawerComponent extends ConsumerStatefulWidget {
const DrawerComponent({
super.key,
this.isOperationExpanded = true,
this.isSettingsExpanded = false,
this.selectedState = const SelectedDrawerState(
menuIndex: 0,
subMenuIndex: 0,
),
});
final bool isOperationExpanded;
final bool isSettingsExpanded;
final SelectedDrawerState selectedState;
@override
ConsumerState<DrawerComponent> createState() => _DrawerComponentState();
}
class _DrawerComponentState extends ConsumerState<DrawerComponent> {
late bool _isOperationExpanded;
late bool _isSettingsExpanded;
@override
void initState() {
super.initState();
_isOperationExpanded = widget.isOperationExpanded;
_isSettingsExpanded = widget.isSettingsExpanded;
}
@override
Widget build(BuildContext context) {
final selected = widget.selectedState;
return Drawer(
backgroundColor: AppTheme.of(context).primaryBackground,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
child: Column(
children: [
const SizedBox(height: 50),
// === Profil utilisateur
Consumer(
builder: (context, ref, child) {
final state = ref.watch(receptionPageModelProvider);
return ListTile(
onTap: () => ProfileRoute().push(context),
contentPadding: EdgeInsets.zero,
leading: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: AppTheme.of(context).secondaryBackground,
borderRadius: BorderRadius.circular(60),
),
),
title: Text(
state.user?.fullName ?? '',
style: AppTheme.of(context).titleMedium,
),
subtitle: Text(
state.user?.email ?? '',
style: AppTheme.of(context).bodyMedium,
),
);
},
),
const Divider(),
// === Opérations
_ExpansionTileComponent(
leadingIcon: Icons.inbox,
isExpanded: _isOperationExpanded,
onExpansionChanged: (expanded) =>
setState(() => _isOperationExpanded = expanded),
title: 'Opérations',
isActive: selected.isSelected(menu: 0),
children: [
_ListTile(
onTap: () {
Navigator.of(context).pop();
ReceptionRoute().go(context);
},
title: 'Réceptions',
isActive: selected.isSelected(menu: 0, sub: 0),
leadingIcon: Icons.move_to_inbox,
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
),
_ListTile(
onTap: () {
Navigator.of(context).pop();
DeliveryRoute().go(context);
},
title: 'Livraisons',
isActive: selected.isSelected(menu: 0, sub: 1),
leadingIcon: Icons.local_shipping,
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
),
_ListTile(
onTap: () {
Navigator.of(context).pop();
InventoryRoute().go(context);
},
title: 'Inventaires',
isActive: selected.isSelected(menu: 0, sub: 2),
leadingIcon: Icons.inventory,
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
),
],
),
// === Produits
_ListTile(
title: "Produits",
leadingIcon: Icons.insert_chart,
trailing: const Icon(Icons.keyboard_arrow_right),
isActive: selected.isSelected(menu: 1),
contentPadding: const EdgeInsetsDirectional.symmetric(
horizontal: 10,
),
),
// === Historique
_ListTile(
title: "Historiques",
leadingIcon: Icons.history,
trailing: const Icon(Icons.keyboard_arrow_right),
isActive: selected.isSelected(menu: 2),
contentPadding: const EdgeInsetsDirectional.symmetric(
horizontal: 10,
),
),
// === Paramètres
_ExpansionTileComponent(
title: "Paramètres",
isExpanded: _isSettingsExpanded,
onExpansionChanged: (expanded) =>
setState(() => _isSettingsExpanded = expanded),
isActive: selected.isSelected(menu: 3),
leadingIcon: Icons.settings,
children: [
_ListTile(
title: 'Connexion Odoo',
isActive: selected.isSelected(menu: 3, sub: 3),
leadingIcon: Icons.lock_open,
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
),
_ListTile(
title: 'Gestion des utilisateurs',
isActive: selected.isSelected(menu: 3, sub: 4),
leadingIcon: Icons.group,
contentPadding: const EdgeInsets.symmetric(horizontal: 40),
),
],
),
const Spacer(),
// === Déconnexion
SafeArea(
child: ListTile(
onTap: () async {
await ref.read(loginPageModelProvider.notifier).logOut();
await UserStruct(id: '1').deleteLocalStorage();
WidgetsBinding.instance.addPostFrameCallback((_) {
SplashRoute().go(context);
});
},
leading: const Icon(Icons.logout),
title: Text(
'Se déconnecter',
style: AppTheme.of(context).bodyLarge,
),
),
),
],
),
),
);
}
}
class SelectedDrawerState {
const SelectedDrawerState({
required this.menuIndex,
required this.subMenuIndex,
});
final int menuIndex;
final int subMenuIndex;
bool isSelected({required int menu, int? sub}) {
if (sub == null) return menuIndex == menu;
return menuIndex == menu && subMenuIndex == sub;
}
}
class _ListTile extends StatelessWidget {
const _ListTile({
required this.title,
this.isActive = false,
this.onTap,
this.leadingIcon,
this.contentPadding,
this.trailing,
});
final bool isActive;
final String title;
final VoidCallback? onTap;
final IconData? leadingIcon;
final EdgeInsetsGeometry? contentPadding;
final Widget? trailing;
@override
Widget build(BuildContext context) {
return ListTile(
selected: isActive,
selectedTileColor: AppTheme.of(context).primary.withValues(alpha: 0.1),
onTap: onTap,
contentPadding: contentPadding,
leading: Icon(
leadingIcon,
color: isActive
? AppTheme.of(context).primary
: AppTheme.of(context).primaryText,
),
title: Text(
title,
style: AppTheme.of(context).bodyLarge.copyWith(
color: isActive ? AppTheme.of(context).primary : null,
),
),
trailing: trailing,
);
}
}
class _ExpansionTileComponent extends StatelessWidget {
const _ExpansionTileComponent({
required this.title,
this.isExpanded = false,
this.onExpansionChanged,
this.isActive = false,
this.children = const <Widget>[],
this.leadingIcon,
});
final bool isExpanded;
final void Function(bool)? onExpansionChanged;
final bool isActive;
final List<Widget> children;
final String title;
final IconData? leadingIcon;
@override
Widget build(BuildContext context) {
return Container(
color: isActive
? AppTheme.of(context).primary.withValues(alpha: 0.05)
: null,
child: ExpansionTile(
initiallyExpanded: isExpanded,
onExpansionChanged: onExpansionChanged,
tilePadding: const EdgeInsetsDirectional.symmetric(horizontal: 10),
shape: LinearBorder.none,
title: Row(
children: [
Icon(
leadingIcon,
color: isActive
? AppTheme.of(context).primary
: AppTheme.of(context).primaryText,
),
const SizedBox(width: 12),
Expanded(
child: Text(
title,
style: AppTheme.of(context).bodyLarge.copyWith(
color: isActive ? AppTheme.of(context).primary : null,
),
),
),
],
),
trailing: Icon(
isExpanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_right,
),
children: children,
),
);
}
}