import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:niogu_app/core/constants/app_color.dart'; import 'package:niogu_app/core/constants/app_font_size.dart'; import 'package:niogu_app/core/providers/app_provider.dart'; import 'package:niogu_app/core/router/app_route.dart'; import 'package:niogu_app/core/services/sync_services.dart'; import 'package:niogu_app/core/utils/log_message.dart'; import 'package:niogu_app/core/utils/login_required.dart'; import 'package:niogu_app/core/enums/sync_status.dart'; import 'package:niogu_app/core/components/modal_outlet_bottom.dart'; import 'package:niogu_app/core/utils/time_zone.dart'; import 'package:niogu_app/core/enums/user_role.dart'; import 'package:niogu_app/core/widgets/custom_snackbar.dart'; import 'package:niogu_app/features/home/presentation/widgets/menu_card.dart'; import 'package:niogu_app/features/home/presentation/widgets/menu_item_card.dart'; import 'package:niogu_app/features/home/presentation/widgets/section_title.dart'; import 'package:niogu_app/features/home/presentation/widgets/sync_icon.dart'; import 'package:niogu_app/features/online_store/presentation/providers/online_store_provider.dart'; import 'package:niogu_app/features/user/domain/entities/user.dart'; import 'package:niogu_app/features/user/presentation/providers/user_provider.dart'; import 'package:sizer/sizer.dart'; class HomeScreen extends ConsumerStatefulWidget { const HomeScreen({super.key}); @override ConsumerState createState() => _HomeScreenState(); } class _HomeScreenState extends ConsumerState { SyncStatus _syncStatus = SyncStatus.synced; bool _isProcessing = false; final List> _ownerActivityMenus = [ {'title': 'Cek Stok', 'icon': Icons.checklist, 'color': Colors.orange}, { 'title': 'Stok Masuk', 'icon': Icons.arrow_circle_down, 'color': Colors.green, }, {'title': 'Pelanggan', 'icon': Icons.person, 'color': Colors.blue}, {'title': 'Pemasok', 'icon': Icons.car_rental, 'color': Colors.purple}, ]; final List> _adminActivityMenus = [ { 'id': 'stock_check', 'title': 'Cek Stok', 'icon': Icons.checklist, 'color': Colors.orange, }, { 'id': 'stock_in', 'title': 'Stok Masuk', 'icon': Icons.arrow_circle_down, 'color': Colors.green, }, { 'id': 'online_order', 'title': 'Pesanan Online', 'icon': Icons.shopping_bag_outlined, 'color': Colors.blue, }, ]; final List> _ownerAssetMenus = [ { "id": "online_store", 'title': 'Toko\nOnline', 'icon': Icons.language, 'color': Colors.indigo, 'firstBadge': 'Gratis', }, { "id": "outlets", 'title': 'Outlet\nUsaha', 'icon': Icons.store, 'color': Colors.teal, 'firstBadge': 'Scale Up', }, ]; @override void initState() { // TODO: implement initState super.initState(); } @override void dispose() { // TODO: implement dispose super.dispose(); } Future _triggerFullSync() async { if (_isProcessing) return; setState(() { _isProcessing = true; _syncStatus = SyncStatus.syncing; }); try { final dio = ref.read(dioProvider); final db = ref.read(appDatabaseProvider); final syncService = SyncService(dio, db); await syncService.restartUpSync(); await syncService.processBatch(); setState(() { _isProcessing = false; _syncStatus = SyncStatus.synced; }); CustomSnackbar.showSuccess(context, "Sinkronisasi berhasil"); } catch (e, st) { LogMessage.log.e(e.toString(), error: e, stackTrace: st); setState(() { _isProcessing = false; _syncStatus = SyncStatus.failed; }); CustomSnackbar.showError( context, "Pastikan teruhubung dengan koneksi internet", ); } } @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { final bool isTablet = 100.w >= 600; final isLoggedIn = ref.watch(currentStatusLoginProvider); final currentUserName = ref.watch(currentUserNameProvider); final currentUserRole = ref.watch(currentUserRoleProvider); final currentOutletName = ref.watch(currentOutletNameProvider); String? badge; if (isLoggedIn) { final badgeCountState = ref.watch( numberOfNeedToBeProcessedStreamProvider, ); badgeCountState.whenData((count) { if (count > 0) badge = count.toString(); }); } ShiftInfo shiftInfo = ShiftInfo( shiftName: '---', shiftStartTime: '---', shiftEndTime: '---', ); if (isLoggedIn) { final shiftInfoState = ref.watch(shiftInfoStreamProvider); shiftInfoState.whenData((s) => shiftInfo = s); } return SafeArea( top: false, bottom: true, right: false, left: false, child: Scaffold( backgroundColor: Colors.white, body: CustomScrollView( slivers: [ SliverToBoxAdapter( child: Stack( clipBehavior: Clip.none, children: [ Container( height: 28.h, padding: EdgeInsets.symmetric( horizontal: 5.w, vertical: 6.h, ), decoration: BoxDecoration( color: AppColor.primaryColor, borderRadius: BorderRadius.only( bottomLeft: Radius.circular(10.w), bottomRight: Radius.circular(10.w), ), ), child: Column( children: [ Row( children: [ if (isLoggedIn) ...[ CircleAvatar( radius: 6.w, backgroundColor: Colors.white24, child: Icon( Icons.person_rounded, size: 10.w, color: Colors.white, ), // Contoh foto user ), SizedBox(width: 3.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Halo, ${currentUserName!}", style: TextStyle( color: Colors.white, fontWeight: FontWeight.w500, fontSize: isTablet ? AppFontSize.medium.sp : AppFontSize.small.sp, ), ), if (currentUserRole == UserRole.admin) ...[ SizedBox(height: 0.5.h), Text( "${shiftInfo.shiftName} : ${shiftInfo.shiftStartTime} ${TimeZone.getCurrentTimeZone()} - ${shiftInfo.shiftEndTime} ${TimeZone.getCurrentTimeZone()}", style: TextStyle( color: Colors.white, fontWeight: FontWeight.w500, fontSize: isTablet ? AppFontSize.medium.sp : AppFontSize.small.sp, ), ), ], SizedBox(height: 0.5.h), GestureDetector( onTap: currentUserRole == UserRole.admin ? null : () { showModalBottomSheet( context: context, useRootNavigator: true, isScrollControlled: true, constraints: const BoxConstraints( maxWidth: double.infinity, ), builder: (context) => const ModalOutletBottom(), ); }, child: Row( mainAxisSize: MainAxisSize.min, children: [ Flexible( child: Text( currentOutletName!, style: TextStyle( color: Colors.white, fontSize: isTablet ? AppFontSize.medium.sp : AppFontSize.small.sp, fontWeight: FontWeight.bold, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), if (currentUserRole == UserRole.owner) ...[ SizedBox(width: 1.w), Icon( Icons .keyboard_arrow_down_rounded, color: Colors.white, size: 5.w, ), ], ], ), ), ], ), ), GestureDetector( onTap: _triggerFullSync, child: Container( padding: EdgeInsets.all(2.w), decoration: BoxDecoration( color: Colors.white.withOpacity( 0.15, ), // Transparan halus shape: BoxShape.circle, ), child: SyncIcon(syncStatus: _syncStatus), ), ), ] else ...[ OutlinedButton.icon( onPressed: () => context.goNamed( AppRoute.ownerLoginScreen, ), icon: Icon( Icons.login_rounded, color: Colors.white, size: 4.5.w, ), label: Text( "Masuk Akun", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: isTablet ? AppFontSize.medium.sp : AppFontSize.small.sp, ), ), style: OutlinedButton.styleFrom( side: const BorderSide( color: Colors.white70, width: 1.5, ), padding: EdgeInsets.symmetric( horizontal: 4.w, vertical: 1.h, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 2.w, ), ), backgroundColor: Colors.white.withOpacity( 0.1, ), ), ), ], if (isTablet) SizedBox(width: 3.w), /** Notification Stack( children: [ IconButton( onPressed: () {}, padding: EdgeInsets.zero, icon: Icon( Icons.notifications_none_rounded, color: Colors.white, size: 7.w, ), ), Positioned( right: isTablet ? 10 : 100.w > 360 ? 12.5 : 15, top: isTablet ? 10 : 100.w > 360 ? 12.5 : 15, child: Container( padding: EdgeInsets.all(0.5.w), decoration: const BoxDecoration( color: Colors.red, shape: BoxShape.circle, ), constraints: BoxConstraints( minWidth: 2.5.w, minHeight: 2.5.w, ), // Dot merah ), ), ], ), */ ], ), ], ), ), Positioned( top: 16.h, left: 0, right: 0, child: SizedBox( height: 18.h, child: PageView.builder( controller: PageController(viewportFraction: 0.9), itemCount: 3, itemBuilder: (context, index) { return Container( margin: EdgeInsets.symmetric(horizontal: 2.w), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5.w), gradient: LinearGradient( colors: index == 0 ? [ Colors.blueAccent, Colors.lightBlueAccent, ] : [ Colors.orangeAccent, Colors.deepOrangeAccent, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), boxShadow: [ BoxShadow( color: AppColor.primaryColor.withOpacity( 0.2, ), blurRadius: 10, offset: const Offset(0, 5), ), ], ), child: Stack( children: [ Positioned( right: -5.w, bottom: -5.w, child: Icon( Icons.sell, color: Colors.white.withOpacity(0.2), size: 30.w, ), ), Padding( padding: EdgeInsets.all(5.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: EdgeInsets.symmetric( horizontal: 2.w, vertical: 0.5.h, ), decoration: BoxDecoration( color: Colors.white24, borderRadius: BorderRadius.circular(2.w), ), child: Text( "Promo Baru", style: TextStyle( color: Colors.white, fontWeight: FontWeight.w500, fontSize: isTablet ? AppFontSize.medium.sp : AppFontSize.small.sp, ), ), ), SizedBox(height: 1.h), Text( "Diskon Spesial Hari Ini!", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: isTablet ? AppFontSize.medium.sp : AppFontSize.small.sp, ), ), ], ), ), ], ), ); }, ), ), ), ], ), ), SliverToBoxAdapter(child: SizedBox(height: 8.h)), /** SliverPadding( padding: EdgeInsets.symmetric(horizontal: 5.w), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1.6, mainAxisSpacing: 2.h, crossAxisSpacing: 3.w, ), delegate: SliverChildBuilderDelegate((context, index) { final menu = _ownerActivityMenus[index]; return MenuItemCard( title: menu['title'], icon: menu['icon'], color: menu['color'], badge: menu['badge'], onTap: () { if (index == 0) { } else if (index == 1) { context.pushNamed(AppRoute.stockInScreen); } }, ); }, childCount: _ownerActivityMenus.length), ), ), */ if (currentUserRole == UserRole.owner || !isLoggedIn) ...[ SectionTitle(title: "Aktivitas Utama"), SliverPadding( padding: EdgeInsets.symmetric(horizontal: 5.w), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, childAspectRatio: 0.8, mainAxisSpacing: 2.h, crossAxisSpacing: 2.w, ), delegate: SliverChildBuilderDelegate((context, index) { final menu = _ownerActivityMenus[index]; return MenuCard( title: menu['title'], icon: menu['icon'], color: menu['color'], onTap: !isLoggedIn ? () => LoginRequired.showLoginRequired(context) : () { if (index == 0) { context.pushNamed( AppRoute.stockCheckScreen, ); } else if (index == 1) { context.pushNamed(AppRoute.stockInScreen); } else if (index == 2) { context.pushNamed(AppRoute.customerScreen); } else if (index == 3) { context.pushNamed(AppRoute.supplierScreen); } }, ); }, childCount: _ownerActivityMenus.length), ), ), SliverToBoxAdapter(child: SizedBox(height: 3.h)), SectionTitle(title: "Aset & Manajemen"), SliverPadding( padding: EdgeInsets.symmetric(horizontal: 5.w), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 1.6, mainAxisSpacing: 2.h, crossAxisSpacing: 3.w, ), delegate: SliverChildBuilderDelegate((context, index) { final menu = _ownerAssetMenus[index]; return MenuItemCard( title: menu['title'], icon: menu['icon'], color: menu['color'], firstBadge: menu['firstBadge'], secondBadge: menu['id'] == 'online_store' && badge != null ? badge : null, onTap: !isLoggedIn ? () => LoginRequired.showLoginRequired(context) : () { if (index == 0) { context.pushNamed( AppRoute.onlineStoreScreen, ); } else if (index == 1) { context.pushNamed(AppRoute.outletScreen); } }, ); }, childCount: _ownerAssetMenus.length), ), ), ] else if (currentUserRole == UserRole.admin) ...[ SectionTitle(title: "Aktivitas Utama"), SliverPadding( padding: EdgeInsets.symmetric(horizontal: 5.w), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 0.8, mainAxisSpacing: 2.h, crossAxisSpacing: 2.w, ), delegate: SliverChildBuilderDelegate((context, index) { final menu = _adminActivityMenus[index]; return MenuCard( title: menu['title'], icon: menu['icon'], color: menu['color'], badge: menu['id'] == 'online_order' && badge != null ? badge : null, onTap: () { if (index == 0) { context.pushNamed(AppRoute.stockCheckScreen); } else if (index == 1) { context.pushNamed(AppRoute.stockInScreen); } else if (index == 2) { context.pushNamed( AppRoute.onlineStoreOrderScreen, ); } }, ); }, childCount: _adminActivityMenus.length), ), ), ], SliverToBoxAdapter(child: SizedBox(height: 12.h)), ], ), ), ); }, ); } }