import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; import 'package:qyuota/config/colors.dart'; import 'package:qyuota/config/images.dart'; import 'package:qyuota/config/text_style.dart'; import 'package:qyuota/view/home/clockin_view.dart'; import 'package:qyuota/view/home/clockout_view.dart'; import 'package:qyuota/view/home/cutipage.dart'; import 'package:qyuota/view/home/statuscuti.dart'; import 'package:qyuota/view/home/timespent_view.dart'; import 'package:qyuota/view/home/daftar_absensi.dart'; import 'package:qyuota/view/home/profile_view.dart'; import 'package:qyuota/services/auth_service.dart'; import 'package:intl/intl.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:flutter/services.dart' show rootBundle; import 'package:http/http.dart' as http; import 'dart:convert'; import 'package:qyuota/config/api_config.dart'; class Announcement { final String title; final String content; Announcement({ required this.title, required this.content, }); factory Announcement.fromJson(Map json) { return Announcement( title: json['title'] ?? '', content: json['content'] ?? '', ); } } class HomeView extends StatefulWidget { const HomeView({Key? key}) : super(key: key); @override State createState() => _HomeViewState(); } final List imageList = [ 'assets/images/aa1.jpg', // Gantilah dengan path gambar yang sesuai 'assets/images/aa2.jpg', 'assets/images/aa3.jpg', ]; class _HomeViewState extends State { Map? userData; Announcement? latestAnnouncement; int totalPresensi = 0; int totalCuti = 0; @override void initState() { super.initState(); _loadUserData(); fetchLatestAnnouncement(); fetchDashboardStats(); } Future _loadUserData() async { final data = await AuthService().getUserData(); setState(() { userData = data; }); } Future fetchLatestAnnouncement() async { try { final token = await AuthService().getToken(); if (token == null) return; final response = await http.get( Uri.parse('${ApiConfig.baseUrl}/api/mobile/announcements/latest'), headers: ApiConfig.authHeaders(token), ); if (response.statusCode == 200) { final data = json.decode(response.body); if (data['success'] && data['data'] != null) { setState(() { latestAnnouncement = Announcement.fromJson(data['data']); }); } } } catch (e) { print('Error fetching announcement: $e'); } } Future fetchDashboardStats() async { try { final token = await AuthService().getToken(); if (token == null) { print('Token is null'); return; } print('Fetching dashboard stats...'); print('URL: ${ApiConfig.baseUrl}/api/mobile/dashboard/stats'); final response = await http.get( Uri.parse('${ApiConfig.baseUrl}/api/mobile/dashboard/stats'), headers: ApiConfig.authHeaders(token), ); print('Response status code: ${response.statusCode}'); print('Response body: ${response.body}'); if (response.statusCode == 200) { final data = json.decode(response.body); print('Decoded data: $data'); print('Data type: ${data.runtimeType}'); if (data['data'] != null) { print('Total presensi: ${data['data']['total_presensi']}'); print('Total cuti: ${data['data']['total_cuti']}'); setState(() { totalPresensi = data['data']['total_presensi'] ?? 0; totalCuti = data['data']['total_cuti'] ?? 0; }); print('State updated - totalPresensi: $totalPresensi, totalCuti: $totalCuti'); } else { print('Data field is null in response'); } } else { print('Error fetching stats: ${response.statusCode}'); print('Error response body: ${response.body}'); } } catch (e, stackTrace) { print('Error fetching stats: $e'); print('Stack trace: $stackTrace'); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: ConstColors.primaryColor, actions: [ IconButton( icon: Icon(Icons.person, color: Colors.white), onPressed: () { Get.to(() => const ProfileView()); }, ), ], ), body: Stack( alignment: Alignment.center, children: [ Column( children: [ SizedBox( height: 300, child: Container( color: ConstColors.primaryColor, child: Padding( padding: const EdgeInsets.only(left: 15, right: 15), child: Column( children: [ SizedBox(height: MediaQuery.of(context).padding.top), Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Halo, ${userData?['name'] ?? 'User'}", style: GoogleFonts.poppins( fontSize: 20, fontWeight: FontWeight.w600, color: ConstColors.whiteColor, letterSpacing: 0.5, ), overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Text( "${userData?['email'] ?? ''}", style: GoogleFonts.poppins( fontSize: 16, fontWeight: FontWeight.w400, color: ConstColors.whiteColor, letterSpacing: 0.3, ), overflow: TextOverflow.ellipsis, ), ], ), ), ], ), const SizedBox(height: 10), Container( height: 180, width: Get.width, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), border: Border.all( color: ConstColors.whiteColor.withOpacity(0.23), ), gradient: LinearGradient( colors: [ ConstColors.whiteColor.withOpacity(0.23), ConstColors.whiteColor.withOpacity(0.05), ], ), ), child: Padding( padding: const EdgeInsets.all(15), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Hello Welcome!", style: pRegular14.copyWith( fontSize: 16, color: ConstColors.whiteColor, ), ), const SizedBox(height: 8), Row( mainAxisSize: MainAxisSize.max, children: [ Icon(Icons.calendar_today, color: Colors.white, size: 18), const SizedBox(width: 8), Expanded( flex: 3, child: Text( "${DateFormat('dd MMM yyyy').format(DateTime.now())}", style: const TextStyle( color: Colors.white, fontSize: 14, ), overflow: TextOverflow.ellipsis, ), ), Expanded( flex: 2, child: Text( "(08:00 - 17:30)", style: const TextStyle( color: Colors.white, fontSize: 13, ), overflow: TextOverflow.ellipsis, textAlign: TextAlign.end, ), ), const SizedBox(width: 8), Icon(Icons.access_time, color: Colors.white.withOpacity(0.5), size: 24), ], ), ], ), ), const SizedBox(height: 20), Row( children: [ Expanded( child: ElevatedButton.icon( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ClockinView(), ), ); }, icon: Icon(Icons.login, color: Colors.white, size: 20), label: Text( "Clock In", style: TextStyle( color: Colors.white, fontSize: 14, ), ), style: ElevatedButton.styleFrom( backgroundColor: ConstColors.skyColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(10), bottomLeft: Radius.circular(10), ), ), padding: EdgeInsets.symmetric(vertical: 12, horizontal: 8), elevation: 0, ), ), ), Container( height: 45, width: 1, color: Colors.white, ), Expanded( child: ElevatedButton.icon( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ClockoutView(), ), ); }, icon: Icon(Icons.logout, color: Colors.white, size: 20), label: Text( "Clock Out", style: TextStyle( color: Colors.white, fontSize: 14, ), ), style: ElevatedButton.styleFrom( backgroundColor: ConstColors.skyColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topRight: Radius.circular(10), bottomRight: Radius.circular(10), ), ), padding: EdgeInsets.symmetric(vertical: 12, horizontal: 8), elevation: 0, ), ), ), ], ), ]), ), ), ], ), ), ), Expanded( child: RefreshIndicator( onRefresh: () async { await _loadUserData(); await fetchDashboardStats(); await fetchLatestAnnouncement(); }, child: ListView( padding: EdgeInsets.zero, physics: const AlwaysScrollableScrollPhysics(), children: [ Padding( padding: const EdgeInsets.only(top: 5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: Get.height * 0.12, child: Padding( padding: EdgeInsets.symmetric( horizontal: Get.width * 0.04, vertical: 6, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Expanded( child: _buildMenuButton( "Status\nCuti", Icons.assignment, Colors.blue[700]!, () { Navigator.push( context, MaterialPageRoute( builder: (context) => StatusCuti(), ), ); }, ), ), SizedBox(width: 16), Expanded( child: _buildMenuButton( "Pengajuan\nCuti", Icons.beach_access, Colors.orange[700]!, () { Navigator.push( context, MaterialPageRoute(builder: (context) => Cutipage()), ); }, ), ), SizedBox(width: 16), Expanded( child: _buildMenuButton( "Daftar\nAbsensi", Icons.list_alt, Colors.green[700]!, () { Navigator.push( context, MaterialPageRoute( builder: (context) => const DaftarAbsensiPage(), ), ); }, ), ), ], ), ), ), const SizedBox(height: 5), Container( margin: EdgeInsets.symmetric( horizontal: Get.width * 0.04, vertical: Get.height * 0.01, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Ringkasan", style: pSemiBold18.copyWith( fontSize: Get.width * 0.04, color: Colors.black87, ), ), SizedBox(height: 12), Row( children: [ _buildInfoCard( "Total Presensi", totalPresensi.toString(), "Hari", Colors.green[100]!, Colors.green[700]!, ), SizedBox(width: 12), _buildInfoCard( "Total Cuti", totalCuti.toString(), "Pengajuan", Colors.orange[100]!, Colors.orange[700]!, ), ], ), ], ), ), const SizedBox(height: 12), Container( margin: EdgeInsets.symmetric( horizontal: Get.width * 0.04, ), child: Text( "Pengumuman", style: pSemiBold18.copyWith( fontSize: Get.width * 0.04, color: Colors.black, ), ), ), const SizedBox(height: 6), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Card( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: Colors.white, width: 1), ), color: Colors.white, child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( latestAnnouncement?.title ?? "Tidak ada pengumuman", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black, ), ), const SizedBox(height: 6), Text( latestAnnouncement?.content ?? "", style: TextStyle( fontSize: 14, color: Colors.black, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ), ), const SizedBox(height: 16), ], ), ), ], ), ), ), ], ), ), ], ), ); } Widget _buildInfoCard(String title, String value, String unit, Color bgColor, Color textColor) { return Expanded( child: Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: bgColor, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( color: textColor, fontSize: Get.width * 0.03, ), ), SizedBox(height: 8), Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( value, style: TextStyle( color: textColor, fontSize: Get.width * 0.07, fontWeight: FontWeight.bold, ), ), SizedBox(width: 4), Text( unit, style: TextStyle( color: textColor, fontSize: Get.width * 0.03, ), ), ], ), ], ), ), ); } } Widget _buildMenuButton( String label, IconData icon, Color color, VoidCallback onTap) { return InkWell( onTap: onTap, child: Container( padding: EdgeInsets.symmetric(horizontal: 6, vertical: 3), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.15), spreadRadius: 1, blurRadius: 3, offset: Offset(0, 2), ), ], ), child: Icon( icon, color: color, size: 24, ), ), SizedBox(height: 4), Text( label, textAlign: TextAlign.center, style: TextStyle( fontSize: 10, color: Colors.black87, fontWeight: FontWeight.w500, height: 1.1, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ); }