import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:generp/screens/hrm/Attendancelist.dart'; import 'package:generp/screens/hrm/ContactList.dart'; import 'package:provider/provider.dart'; import '../../Utils/app_colors.dart'; import 'AdvanceListScreen.dart'; import 'CasualLeaveHistoryScreen.dart'; import 'LeaveApplicationScreen.dart'; import 'TourExpensesListScreen.dart'; import 'RewardListScreen.dart'; import '../../Notifiers/hrmProvider/hrmAccessiblePagesProvider.dart'; import 'oggchart.dart'; class HrmdashboardScreen extends StatefulWidget { const HrmdashboardScreen({super.key}); @override State createState() => _HrmdashboardScreenState(); } class _HrmdashboardScreenState extends State { final allowedPages = [ "Team Leave Request Approval", "Team Attendance Approval", "Leave Request List", "Tour Bill List", "Rewards List", "Attendance Request List", "Advance List", "Casual Leave List", ]; // Responsive text size function double getResponsiveTextSize(BuildContext context, double baseSize) { final double scale = MediaQuery.of(context).textScaleFactor; final double width = MediaQuery.of(context).size.width; if (width < 360) { // Small phones return baseSize * 0.85; } else if (width < 400) { // Medium phones return baseSize; } else { // Large phones return baseSize * 1.1; } } // Responsive padding function double getResponsivePadding(BuildContext context) { final double width = MediaQuery.of(context).size.width; return width * 0.04; // 4% of screen width } // Responsive height function double getResponsiveHeight(BuildContext context, double baseHeight) { final double height = MediaQuery.of(context).size.height; if (height < 700) { // Small height devices return baseHeight * 0.85; } else if (height < 800) { // Medium height devices return baseHeight; } else { // Large height devices return baseHeight * 1.15; } } @override void initState() { super.initState(); Future.microtask( () => Provider.of( context, listen: false, ).fetchAccessiblePages(context), ); } @override Widget build(BuildContext context) { final bool isSmallScreen = MediaQuery.of(context).size.width < 360; final bool isLargeScreen = MediaQuery.of(context).size.width > 400; return SafeArea( top: false, child: Scaffold( appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: const Color(0xFFCEEDFF), title: Row( children: [ InkResponse( onTap: () => Navigator.pop(context, true), child: SvgPicture.asset( "assets/svg/appbar_back_button.svg", height: isSmallScreen ? 22 : 25, ), ), SizedBox(width: isSmallScreen ? 8 : 10), Text( "HRM", style: TextStyle( fontSize: getResponsiveTextSize(context, 18), fontFamily: "Plus Jakarta Sans", fontWeight: FontWeight.w600, color: AppColors.semi_black, ), ), ], ), ), backgroundColor: AppColors.scaffold_bg_color, body: SingleChildScrollView( child: Column( children: [ /// Background Stack( children: [ Container( width: double.infinity, height: getResponsiveHeight(context, 490), color: const Color(0xffF6F6F8), ), Container( width: double.infinity, height: getResponsiveHeight(context, 490), padding: EdgeInsets.only( top: 1, bottom: getResponsiveHeight(context, 30) ), decoration: const BoxDecoration( gradient: LinearGradient( colors: [ Color(0xFFCEEDFF), Color(0xFFf9f9fb), Color(0xffF6F6F8), ], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), ), Container( width: double.infinity, padding: EdgeInsets.only( top: 1, bottom: getResponsiveHeight(context, 30) ), child: Image.asset( "assets/images/vector.png", height: getResponsiveHeight(context, 230), width: double.infinity, fit: BoxFit.fitWidth, ), ), /// Content Column( children: [ /// Top Illustration & Button Container( width: double.infinity, padding: EdgeInsets.only( top: getResponsiveHeight(context, 60), bottom: getResponsiveHeight(context, 30) ), child: Column( children: [ SvgPicture.asset( "assets/images/capa.svg", height: getResponsiveHeight(context, 146), width: MediaQuery.of(context).size.width * 0.9, ), SizedBox(height: getResponsiveHeight(context, 32)), Container( padding: EdgeInsets.symmetric( horizontal: isSmallScreen ? 16 : 20, vertical: isSmallScreen ? 6 : 8, ), decoration: BoxDecoration( border: Border.all( color: const Color(0xFF1487C9), width: 1.2, ), color: const Color(0xffEDF8FF), borderRadius: BorderRadius.circular(30), ), child: InkWell( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => OrgChartt(), ), ); }, child: Row( mainAxisSize: MainAxisSize.min, children: [ SvgPicture.asset( "assets/svg/hrm/groupIc.svg", height: isSmallScreen ? 25 : 29, width: isSmallScreen ? 25 : 29, fit: BoxFit.contain, ), SizedBox(width: isSmallScreen ? 5 : 7), Flexible( child: Text( "Organization Structure", style: TextStyle( fontSize: getResponsiveTextSize(context, 15), fontWeight: FontWeight.w500, fontStyle: FontStyle.normal, fontFamily: "Plus Jakarta Sans", ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Icon( Icons.chevron_right, color: Colors.black54, size: isSmallScreen ? 18 : 20, ), ], ), ), ), ], ), ), /// Grid Section LayoutBuilder( builder: (context, constraints) { final screenWidth = constraints.maxWidth; final crossAxisCount = (screenWidth / 180).floor().clamp(2, 4); final childAspectRatio = screenWidth < 360 ? 1.5 : 1.7; return Padding( padding: EdgeInsets.symmetric( horizontal: getResponsivePadding(context)-3, vertical: 10, ), child: Consumer( builder: (context, provider, child) { if (provider.isLoading) { return const Center( child: CircularProgressIndicator(), ); } if (provider.errorMessage != null) { return Center( child: Text( provider.errorMessage!, style: TextStyle( fontSize: getResponsiveTextSize(context, 14), ), ), ); } final pages = (provider.response?.pagesAccessible ?? []) .where( (page) => allowedPages.contains( page.pageName, ), ).toList(); return GridView.builder( itemCount: pages.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: crossAxisCount, crossAxisSpacing: isSmallScreen ? 2 : 4, mainAxisSpacing: isSmallScreen ? 2 : 4, childAspectRatio: childAspectRatio, ), itemBuilder: (context, index) { final page = pages[index]; return _buildTile( context: context, label: page.pageName ?? "", subtitle: _getSubtitle( page.pageName ?? "", ), assetIcon: _getIcon(page.pageName ?? ""), txtColor: const Color(0xff1487C9), onTap: () => _handleNavigation( context, page.pageName ?? "", page.mode ?? "", ), ); }, ); }, ), ); }, ), SizedBox(height: getResponsiveHeight(context, 40)), ], ), ], ), ], ), ), ), ); } /// Card builder Widget _buildTile({ required BuildContext context, required String label, required String subtitle, required String assetIcon, required Color txtColor, VoidCallback? onTap, }) { final bool isSmallScreen = MediaQuery.of(context).size.width < 360; return LayoutBuilder( builder: (context, constraints) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(14), child: Container( padding: EdgeInsets.symmetric( vertical: constraints.maxHeight * 0.08, horizontal: constraints.maxWidth * 0.06, ), margin: EdgeInsets.symmetric( vertical: isSmallScreen ? 4 : 6.5, horizontal: isSmallScreen ? 2 : 4 ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(14), // boxShadow: [ // BoxShadow( // color: Colors.black12, // blurRadius: 4, // offset: Offset(0, 2), // ), // ], ), child: Row( children: [ Expanded( flex: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Flexible( child: Text( label, style: TextStyle( fontSize: getResponsiveTextSize(context, 14), color: AppColors.app_blue, fontFamily: "JakartaMedium", height: 1.2, ), softWrap: true, overflow: TextOverflow.ellipsis, maxLines: isSmallScreen ? 2 : 3, ), ), SizedBox(height: isSmallScreen ? 2 : 6), Flexible( child: Text( subtitle, style: TextStyle( fontSize: getResponsiveTextSize(context, 12), color: AppColors.grey_semi, fontFamily: "JakartaMedium", height: 1, ), softWrap: true, overflow: TextOverflow.ellipsis, maxLines: 2, ), ), ], ), ), Expanded( flex: 1, child: Container( height: constraints.maxHeight * 0.45, width: constraints.maxHeight * 0.45, decoration: BoxDecoration( shape: BoxShape.circle, color: const Color(0xFFEDF8FF), ), child: Center( child: SvgPicture.asset( assetIcon, height: constraints.maxHeight * 0.22, width: constraints.maxHeight * 0.22, ), ), ), ), ], ), ), ); }, ); } /// Mapping subtitles String _getSubtitle(String pageName) { switch (pageName) { case "Attendance Request List": return "Real-time request"; case "Leave Request List": return "Apply & Track"; case "Rewards List": return "Track earned rewards"; case "Tour Bill List": return "Submit and manage claims"; case "Team Leave Request Approval": return "Approve & Reject"; case "Team Attendance Approval": return "Team Attendance Request"; case "Advance List": return "Advance Payment"; case "Casual Leave List": return "Track Casual Leave"; case "Employee Contact List": return "Staff Contact"; default: return ""; } } /// Mapping icons String _getIcon(String pageName) { switch (pageName) { case "Attendance Request List": return "assets/svg/hrm/attendanceList.svg"; case "Leave Request List": return "assets/svg/hrm/leaveApplication.svg"; case "Rewards List": return "assets/svg/hrm/rewardList.svg"; case "Tour Bill List": return "assets/svg/hrm/tourExp.svg"; case "Team Leave Request Approval": return "assets/svg/hrm/logout_ic.svg"; case "Team Attendance Approval": return "assets/svg/hrm/check_ic.svg"; case "Advance List": return "assets/svg/hrm/advance_list_ic.svg"; case "Casual Leave List": return "assets/svg/hrm/casual_leave_history_ic.svg"; case "Employee Contact List": return "assets/svg/hrm/emp_contact_list.svg"; default: return "assets/svg/hrm/groupIc.svg"; } } /// Navigation mapping void _handleNavigation(BuildContext context, String pageName, String mode) { switch (pageName) { case "Attendance Request List": Navigator.push( context, MaterialPageRoute( builder: (context) => AttendanceListScreen(mode: mode), ), ); break; case "Leave Request List": Navigator.push( context, MaterialPageRoute( builder: (context) => LeaveApplicationListScreen(mode: mode), ), ); break; case "Rewards List": Navigator.push( context, MaterialPageRoute(builder: (context) => RewardListScreen()), ); break; case "Tour Bill List": Navigator.push( context, MaterialPageRoute(builder: (context) => TourExpensesListScreen()), ); break; case "Team Leave Request Approval": Navigator.push( context, MaterialPageRoute( builder: (context) => LeaveApplicationListScreen(mode: mode), ), ); break; case "Team Attendance Approval": Navigator.push( context, MaterialPageRoute( builder: (context) => AttendanceListScreen(mode: mode), ), ); break; case "Advance List": Navigator.push( context, MaterialPageRoute( builder: (context) => AdvanceListScreen(), ), ); break; case "Casual Leave List": Navigator.push( context, MaterialPageRoute( builder: (context) => CasualLeaveHistoryScreen(), ), ); break; case "Employee Contact List": Navigator.push( context, MaterialPageRoute( builder: (context) => ContactListScreen(), ), ); break; } } }