marco.pms.mobileapp/lib/view/layouts/user_profile_right_bar.dart

320 lines
10 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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/employee_info.dart';
import 'package:marco/helpers/widgets/avatar.dart';
class UserProfileBar extends StatefulWidget {
final bool isCondensed;
const UserProfileBar({super.key, this.isCondensed = false});
@override
_UserProfileBarState createState() => _UserProfileBarState();
}
class _UserProfileBarState extends State<UserProfileBar>
with SingleTickerProviderStateMixin, UIMixin {
final ThemeCustomizer customizer = ThemeCustomizer.instance;
bool isCondensed = false;
EmployeeInfo? employeeInfo;
@override
void initState() {
super.initState();
_loadEmployeeInfo();
}
void _loadEmployeeInfo() {
setState(() {
employeeInfo = LocalStorage.getEmployeeInfo();
});
}
@override
Widget build(BuildContext context) {
isCondensed = widget.isCondensed;
return MyCard(
borderRadiusAll: 16,
paddingAll: 0,
shadow: MyShadow(position: MyShadowPosition.centerRight, elevation: 4),
child: AnimatedContainer(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
leftBarTheme.background.withOpacity(0.95),
leftBarTheme.background.withOpacity(0.85),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
width: isCondensed ? 90 : 250,
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: SafeArea(
bottom: true,
top: false,
left: false,
right: false,
child: Column(
children: [
userProfileSection(),
MySpacing.height(8),
supportAndSettingsMenu(),
const Spacer(),
logoutButton(),
],
),
),
),
);
}
Widget userProfileSection() {
if (employeeInfo == null) {
return const Padding(
padding: EdgeInsets.all(24.0),
child: Center(child: CircularProgressIndicator()),
);
}
return Container(
width: double.infinity,
padding: MySpacing.xy(58, 68),
decoration: BoxDecoration(
color: leftBarTheme.activeItemBackground,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: Column(
children: [
Avatar(
firstName: employeeInfo?.firstName ?? 'First',
lastName: employeeInfo?.lastName ?? 'Name',
size: 60,
),
MySpacing.height(12),
MyText.labelLarge(
"${employeeInfo?.firstName ?? 'First'} ${employeeInfo?.lastName ?? 'Last'}",
fontWeight: 700,
color: leftBarTheme.activeItemColor,
textAlign: TextAlign.center,
),
],
),
);
}
Widget supportAndSettingsMenu() {
return Padding(
padding: MySpacing.xy(16, 16),
child: Column(
children: [
menuItem(icon: LucideIcons.settings, label: "Settings"),
MySpacing.height(12),
menuItem(icon: LucideIcons.badge_help, label: "Support"),
],
),
);
}
Widget menuItem({required IconData icon, required String label}) {
return InkWell(
onTap: () {},
borderRadius: BorderRadius.circular(10),
hoverColor: leftBarTheme.activeItemBackground.withOpacity(0.2),
splashColor: leftBarTheme.activeItemBackground.withOpacity(0.3),
child: Padding(
padding: MySpacing.xy(12, 10),
child: Row(
children: [
Icon(icon, size: 20, color: leftBarTheme.onBackground),
MySpacing.width(12),
Expanded(
child: MyText.bodyMedium(
label,
color: leftBarTheme.onBackground,
fontWeight: 500,
),
),
],
),
),
);
}
Widget logoutButton() {
return InkWell(
onTap: () async {
bool? confirm = await showDialog<bool>(
context: context,
builder: (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: () async {
await LocalStorage.logout();
},
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"),
),
),
],
)
],
),
),
);
},
);
if (confirm == true) {
// Show animated loader dialog
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => Dialog(
backgroundColor: Colors.transparent,
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [
CircularProgressIndicator(),
SizedBox(height: 12),
Text(
"Logging you out...",
style: TextStyle(color: Colors.white),
)
],
),
),
);
await LocalStorage.logout();
if (mounted) {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
const Icon(LucideIcons.check, color: Colors.green),
const SizedBox(width: 12),
const Text("Youve been logged out successfully."),
],
),
backgroundColor: Colors.grey.shade900,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
duration: const Duration(seconds: 3),
),
);
}
}
},
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(16),
bottomRight: Radius.circular(16),
),
hoverColor: leftBarTheme.activeItemBackground.withOpacity(0.2),
splashColor: leftBarTheme.activeItemBackground.withOpacity(0.3),
child: AnimatedContainer(
duration: const Duration(milliseconds: 150),
curve: Curves.easeInOut,
width: double.infinity,
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,
),
],
),
),
);
}
}