import 'package:flutter/material.dart'; import 'package:marco/helpers/theme/theme_customizer.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; import 'package:marco/helpers/utils/my_shadow.dart'; import 'package:marco/helpers/widgets/my_card.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:marco/model/employees/employee_info.dart'; import 'package:marco/helpers/widgets/avatar.dart'; import 'package:get/get.dart'; import 'package:marco/controller/auth/mpin_controller.dart'; class UserProfileBar extends StatefulWidget { final bool isCondensed; const UserProfileBar({super.key, this.isCondensed = false}); @override _UserProfileBarState createState() => _UserProfileBarState(); } class _UserProfileBarState extends State with SingleTickerProviderStateMixin, UIMixin { final ThemeCustomizer customizer = ThemeCustomizer.instance; bool isCondensed = false; EmployeeInfo? employeeInfo; bool hasMpin = true; @override void initState() { super.initState(); _loadEmployeeInfo(); _checkMpinStatus(); } void _loadEmployeeInfo() { setState(() { employeeInfo = LocalStorage.getEmployeeInfo(); }); } Future _checkMpinStatus() async { final bool mpinStatus = await LocalStorage.getIsMpin(); setState(() { hasMpin = mpinStatus; }); } @override Widget build(BuildContext context) { isCondensed = widget.isCondensed; return MyCard( borderRadiusAll: 16, paddingAll: 0, shadow: MyShadow( position: MyShadowPosition.centerRight, elevation: 6, blurRadius: 12, ), child: AnimatedContainer( decoration: BoxDecoration( gradient: LinearGradient( colors: [ leftBarTheme.background.withOpacity(0.97), leftBarTheme.background.withOpacity(0.88), ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), width: isCondensed ? 90 : 260, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, child: SafeArea( bottom: true, top: false, left: false, right: false, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ userProfileSection(), MySpacing.height(16), supportAndSettingsMenu(), const Spacer(), logoutButton(), ], ), ), ), ); } /// User Profile Section - Avatar + Name Widget userProfileSection() { if (employeeInfo == null) { return const Padding( padding: EdgeInsets.symmetric(vertical: 32), child: Center(child: CircularProgressIndicator()), ); } return Container( width: double.infinity, padding: MySpacing.fromLTRB(20, 50, 30, 50), decoration: BoxDecoration( color: leftBarTheme.activeItemBackground, borderRadius: const BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), child: Row( children: [ Avatar( firstName: employeeInfo?.firstName ?? 'F', lastName: employeeInfo?.lastName ?? 'N', size: 50, ), MySpacing.width(12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MyText.bodyMedium( "${employeeInfo?.firstName ?? 'First'} ${employeeInfo?.lastName ?? 'Last'}", fontWeight: 700, color: leftBarTheme.activeItemColor, ), ], ), ), ], ), ); } /// Menu Section with Settings, Support & MPIN Widget supportAndSettingsMenu() { return Padding( padding: MySpacing.xy(16, 16), child: Column( children: [ menuItem( icon: LucideIcons.settings, label: "Settings", ), MySpacing.height(14), menuItem( icon: LucideIcons.badge_help, label: "Support", ), MySpacing.height(14), menuItem( icon: LucideIcons.lock, label: hasMpin ? "Change MPIN" : "Set MPIN", iconColor: hasMpin ? leftBarTheme.onBackground : Colors.redAccent, labelColor: hasMpin ? leftBarTheme.onBackground : Colors.redAccent, onTap: () { final controller = Get.put(MPINController()); if (hasMpin) { controller.setChangeMpinMode(); } Navigator.pushNamed(context, "/auth/mpin-auth"); }, filled: true, ), ], ), ); } Widget menuItem({ required IconData icon, required String label, Color? iconColor, Color? labelColor, VoidCallback? onTap, bool filled = false, }) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(12), hoverColor: leftBarTheme.activeItemBackground.withOpacity(0.25), splashColor: leftBarTheme.activeItemBackground.withOpacity(0.35), child: Container( padding: MySpacing.xy(14, 12), decoration: BoxDecoration( color: filled ? leftBarTheme.activeItemBackground.withOpacity(0.15) : Colors.transparent, borderRadius: BorderRadius.circular(12), border: Border.all( color: filled ? leftBarTheme.activeItemBackground.withOpacity(0.3) : Colors.transparent, width: 1, ), ), child: Row( children: [ Icon(icon, size: 22, color: iconColor ?? leftBarTheme.onBackground), MySpacing.width(14), Expanded( child: MyText.bodyMedium( label, color: labelColor ?? leftBarTheme.onBackground, fontWeight: 600, ), ), ], ), ), ); } /// Logout Button Widget logoutButton() { return InkWell( onTap: () async { await _showLogoutConfirmation(); }, borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(16), bottomRight: Radius.circular(16), ), hoverColor: leftBarTheme.activeItemBackground.withOpacity(0.25), splashColor: leftBarTheme.activeItemBackground.withOpacity(0.35), child: Container( padding: MySpacing.all(16), decoration: BoxDecoration( color: leftBarTheme.activeItemBackground, borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(16), bottomRight: Radius.circular(16), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ MyText.bodyMedium( "Logout", color: leftBarTheme.activeItemColor, fontWeight: 600, ), MySpacing.width(8), Icon( LucideIcons.log_out, size: 20, color: leftBarTheme.activeItemColor, ), ], ), ), ); } Future _showLogoutConfirmation() async { bool? confirm = await showDialog( context: context, builder: (context) => _buildLogoutDialog(context), ); if (confirm == true) { await LocalStorage.logout(); } } Widget _buildLogoutDialog(BuildContext context) { return Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 28), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(LucideIcons.log_out, size: 48, color: Colors.redAccent), const SizedBox(height: 16), Text( "Logout Confirmation", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w700, color: Theme.of(context).colorScheme.onBackground, ), ), const SizedBox(height: 12), Text( "Are you sure you want to logout?\nYou will need to login again to continue.", textAlign: TextAlign.center, style: TextStyle( fontSize: 14, color: Theme.of(context).colorScheme.onSurface.withOpacity(0.7), ), ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: TextButton( onPressed: () => Navigator.pop(context, false), style: TextButton.styleFrom( foregroundColor: Colors.grey.shade700, ), child: const Text("Cancel"), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: () => Navigator.pop(context, true), style: ElevatedButton.styleFrom( backgroundColor: Colors.redAccent, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text("Logout"), ), ), ], ), ], ), ), ); } }