290 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			290 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| import 'package:marco/helpers/theme/app_theme.dart';
 | |
| import 'package:marco/helpers/theme/theme_customizer.dart';
 | |
| import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
 | |
| import 'package:marco/helpers/utils/my_shadow.dart';
 | |
| import 'package:marco/helpers/widgets/my_button.dart';
 | |
| import 'package:marco/helpers/widgets/my_card.dart';
 | |
| import 'package:marco/helpers/widgets/my_container.dart';
 | |
| import 'package:marco/helpers/widgets/my_dashed_divider.dart';
 | |
| import 'package:marco/helpers/widgets/my_spacing.dart';
 | |
| import 'package:marco/helpers/widgets/my_text.dart';
 | |
| import 'package:marco/helpers/widgets/my_text_style.dart';
 | |
| import 'package:marco/widgets/custom_pop_menu.dart';
 | |
| import 'package:flutter/material.dart';
 | |
| import 'package:flutter_lucide/flutter_lucide.dart';
 | |
| import 'package:marco/helpers/services/storage/local_storage.dart';
 | |
| import 'package:marco/model/employee_info.dart';
 | |
| import 'package:marco/helpers/widgets/avatar.dart';
 | |
| 
 | |
| class TopBar extends StatefulWidget {
 | |
|   const TopBar({super.key});
 | |
| 
 | |
|   @override
 | |
|   _TopBarState createState() => _TopBarState();
 | |
| }
 | |
| 
 | |
| class _TopBarState extends State<TopBar>
 | |
|     with SingleTickerProviderStateMixin, UIMixin {
 | |
|   Function? languageHideFn;
 | |
|   EmployeeInfo? employeeInfo;
 | |
| 
 | |
|   @override
 | |
|   void initState() {
 | |
|     super.initState();
 | |
|     _loadEmployeeInfo();
 | |
|   }
 | |
| 
 | |
|   void _loadEmployeeInfo() {
 | |
|     setState(() {
 | |
|       employeeInfo = LocalStorage.getEmployeeInfo();
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   Widget build(BuildContext context) {
 | |
|     return MyCard(
 | |
|       shadow: MyShadow(position: MyShadowPosition.bottomRight, elevation: 0.5),
 | |
|       height: 60,
 | |
|       borderRadiusAll: 0,
 | |
|       padding: MySpacing.x(24),
 | |
|       color: topBarTheme.background.withAlpha(246),
 | |
|       child: Row(
 | |
|         children: [
 | |
|           Row(
 | |
|             children: [
 | |
|               InkWell(
 | |
|                   splashColor: colorScheme.onSurface,
 | |
|                   highlightColor: colorScheme.onSurface,
 | |
|                   onTap: () {
 | |
|                     ThemeCustomizer.toggleLeftBarCondensed();
 | |
|                   },
 | |
|                   child: Icon(
 | |
|                     Icons.menu,
 | |
|                     color: topBarTheme.onBackground,
 | |
|                   )),
 | |
|               MySpacing.width(24),
 | |
|               SizedBox(
 | |
|                 width: 200,
 | |
|                 child: TextFormField(
 | |
|                   maxLines: 1,
 | |
|                   style: MyTextStyle.bodyMedium(),
 | |
|                   decoration: InputDecoration(
 | |
|                       hintText: "Search",
 | |
|                       hintStyle: MyTextStyle.bodySmall(xMuted: true),
 | |
|                       border: outlineInputBorder,
 | |
|                       enabledBorder: outlineInputBorder,
 | |
|                       focusedBorder: focusedInputBorder,
 | |
|                       prefixIcon: Align(
 | |
|                           alignment: Alignment.center,
 | |
|                           child: Icon(
 | |
|                             LucideIcons.search,
 | |
|                             size: 14,
 | |
|                           )),
 | |
|                       prefixIconConstraints: BoxConstraints(
 | |
|                           minWidth: 36,
 | |
|                           maxWidth: 36,
 | |
|                           minHeight: 32,
 | |
|                           maxHeight: 32),
 | |
|                       contentPadding: MySpacing.xy(16, 12),
 | |
|                       isCollapsed: true,
 | |
|                       floatingLabelBehavior: FloatingLabelBehavior.never),
 | |
|                 ),
 | |
|               ),
 | |
|             ],
 | |
|           ),
 | |
|           Expanded(
 | |
|             child: Row(
 | |
|               mainAxisAlignment: MainAxisAlignment.end,
 | |
|               children: [
 | |
|                 MySpacing.width(6),
 | |
|                 CustomPopupMenu(
 | |
|                   backdrop: true,
 | |
|                   onChange: (_) {},
 | |
|                   offsetX: -120,
 | |
|                   menu: Padding(
 | |
|                     padding: MySpacing.xy(8, 8),
 | |
|                     child: Center(
 | |
|                       child: Icon(
 | |
|                         LucideIcons.bell,
 | |
|                         size: 18,
 | |
|                       ),
 | |
|                     ),
 | |
|                   ),
 | |
|                   menuBuilder: (_) => buildNotifications(),
 | |
|                 ),
 | |
|                 MySpacing.width(4),
 | |
|                 CustomPopupMenu(
 | |
|                   backdrop: true,
 | |
|                   onChange: (_) {},
 | |
|                   offsetX: -60,
 | |
|                   offsetY: 8,
 | |
|                   menu: Padding(
 | |
|                     padding: MySpacing.xy(8, 8),
 | |
|                     child: Row(
 | |
|                       crossAxisAlignment: CrossAxisAlignment.center,
 | |
|                       children: [
 | |
|                         Avatar(
 | |
|                           firstName: employeeInfo?.firstName ?? 'First',
 | |
|                           lastName: employeeInfo?.lastName ?? 'Name',
 | |
|                           size: 31,
 | |
|                         ),
 | |
|                         MySpacing.width(8),
 | |
|                         MyText.labelSmall(
 | |
|                           "${employeeInfo?.firstName ?? 'First Name'} ${employeeInfo?.lastName ?? 'Last Name'}",
 | |
|                           fontWeight: 600,
 | |
|                           muted: true,
 | |
|                         ),
 | |
|                       ],
 | |
|                     ),
 | |
|                   ),
 | |
|                   menuBuilder: (_) => buildAccountMenu(),
 | |
|                   hideFn: (hide) => languageHideFn = hide,
 | |
|                 ),
 | |
|               ],
 | |
|             ),
 | |
|           )
 | |
|         ],
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   Widget buildNotifications() {
 | |
|     Widget buildNotification(String title, String description) {
 | |
|       return Column(
 | |
|         crossAxisAlignment: CrossAxisAlignment.start,
 | |
|         children: [
 | |
|           MyText.labelLarge(title),
 | |
|           MySpacing.height(4),
 | |
|           MyText.bodySmall(description)
 | |
|         ],
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     return MyContainer.bordered(
 | |
|       paddingAll: 0,
 | |
|       width: 250,
 | |
|       child: Column(
 | |
|         crossAxisAlignment: CrossAxisAlignment.start,
 | |
|         children: [
 | |
|           Padding(
 | |
|             padding: MySpacing.xy(16, 12),
 | |
|             child: MyText.titleMedium("Notification", fontWeight: 600),
 | |
|           ),
 | |
|           MyDashedDivider(
 | |
|               height: 1, color: theme.dividerColor, dashSpace: 4, dashWidth: 6),
 | |
|           Padding(
 | |
|             padding: MySpacing.xy(16, 12),
 | |
|             child: Column(
 | |
|               crossAxisAlignment: CrossAxisAlignment.start,
 | |
|               children: [
 | |
|                 buildNotification("Missed Check-in",
 | |
|                     "You missed check-in for Project Alpha on 21 May 2025."),
 | |
|                 MySpacing.height(12),
 | |
|                 buildNotification("Approval Required",
 | |
|                     "Regularization request pending approval for 20 May 2025."),
 | |
|                 MySpacing.height(12),
 | |
|                 buildNotification("Attendance Reminder",
 | |
|                     "Please check out before 6:00 PM today."),
 | |
|                 MySpacing.height(12),
 | |
|                 buildNotification("Late Check-out",
 | |
|                     "Your last check-out on 19 May 2025 was late by 15 minutes."),
 | |
|               ],
 | |
|             ),
 | |
|           ),
 | |
|           MyDashedDivider(
 | |
|               height: 1, color: theme.dividerColor, dashSpace: 4, dashWidth: 6),
 | |
|           Padding(
 | |
|             padding: MySpacing.xy(16, 0),
 | |
|             child: Row(
 | |
|               mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | |
|               children: [
 | |
|                 MyButton.text(
 | |
|                   onPressed: () {},
 | |
|                   splashColor: contentTheme.primary.withAlpha(28),
 | |
|                   child: MyText.labelSmall(
 | |
|                     "View All",
 | |
|                     color: contentTheme.primary,
 | |
|                   ),
 | |
|                 ),
 | |
|                 MyButton.text(
 | |
|                   onPressed: () {},
 | |
|                   splashColor: contentTheme.danger.withAlpha(28),
 | |
|                   child: MyText.labelSmall(
 | |
|                     "Clear",
 | |
|                     color: contentTheme.danger,
 | |
|                   ),
 | |
|                 ),
 | |
|               ],
 | |
|             ),
 | |
|           )
 | |
|         ],
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   Widget buildAccountMenu() {
 | |
|     return MyContainer.bordered(
 | |
|       paddingAll: 0,
 | |
|       width: 150,
 | |
|       child: Column(
 | |
|         crossAxisAlignment: CrossAxisAlignment.start,
 | |
|         children: [
 | |
|           Padding(
 | |
|             padding: MySpacing.xy(8, 8),
 | |
|             child: Column(
 | |
|               crossAxisAlignment: CrossAxisAlignment.start,
 | |
|               children: [
 | |
|                 MyButton(
 | |
|                   onPressed: () => {},
 | |
|                   tapTargetSize: MaterialTapTargetSize.shrinkWrap,
 | |
|                   borderRadiusAll: AppStyle.buttonRadius.medium,
 | |
|                   padding: MySpacing.xy(8, 4),
 | |
|                   splashColor: colorScheme.onSurface.withAlpha(20),
 | |
|                   backgroundColor: Colors.transparent,
 | |
|                   child: Row(
 | |
|                     children: [
 | |
|                       Icon(
 | |
|                         LucideIcons.user,
 | |
|                         size: 14,
 | |
|                         color: contentTheme.onBackground,
 | |
|                       ),
 | |
|                       MySpacing.width(8),
 | |
|                       MyText.labelMedium(
 | |
|                         "My Account",
 | |
|                         fontWeight: 600,
 | |
|                       ),
 | |
|                     ],
 | |
|                   ),
 | |
|                 ),
 | |
|                 MySpacing.height(4),
 | |
|                 MyButton(
 | |
|                   tapTargetSize: MaterialTapTargetSize.shrinkWrap,
 | |
|                   onPressed: () => {},
 | |
|                   borderRadiusAll: AppStyle.buttonRadius.medium,
 | |
|                   padding: MySpacing.xy(8, 4),
 | |
|                   splashColor: colorScheme.onSurface.withAlpha(20),
 | |
|                   backgroundColor: Colors.transparent,
 | |
|                   child: Row(
 | |
|                     children: [
 | |
|                       Icon(
 | |
|                         LucideIcons.settings,
 | |
|                         size: 14,
 | |
|                         color: contentTheme.onBackground,
 | |
|                       ),
 | |
|                       MySpacing.width(8),
 | |
|                       MyText.labelMedium(
 | |
|                         "Settings",
 | |
|                         fontWeight: 600,
 | |
|                       ),
 | |
|                     ],
 | |
|                   ),
 | |
|                 ),
 | |
|               ],
 | |
|             ),
 | |
|           ),
 | |
|         ],
 | |
|       ),
 | |
|     );
 | |
|   }
 | |
| }
 |