- Updated import paths for employee model files to reflect new directory structure. - Deleted obsolete models: JobRecentApplicationModel, LeadReportModel, Product, ProductOrderModal, ProjectSummaryModel, RecentOrderModel, TaskListModel, TimeLineModel, User, VisitorByChannelsModel. - Introduced new AttendanceLogModel, AttendanceLogViewModel, AttendanceModel, TaskModel, TaskListModel, EmployeeInfo, and EmployeeModel with comprehensive fields and JSON serialization methods. - Enhanced data handling in attendance and task management features.
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/employees/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,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|