import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'dart:async'; import 'package:url_launcher/url_launcher.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../config.dart'; import 'profile.dart'; import '../staf/home/payments.dart'; class BerandaPage extends StatefulWidget { final Map userData; const BerandaPage({super.key, required this.userData}); @override State createState() => _BerandaPageState(); } class _BerandaPageState extends State { int _selectedIndex = 0; @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF7F9FB), // Matches staff background body: IndexedStack( index: _selectedIndex, children: [ HomeDriverTab(userData: widget.userData), ProfilePage(userData: widget.userData), ], ), bottomNavigationBar: _buildPersistentBottomNav(), ); } Widget _buildPersistentBottomNav() { return Container( height: 64 + MediaQuery.of(context).padding.bottom, decoration: BoxDecoration( color: const Color(0xFFFFFFFF).withOpacity(0.95), border: const Border(top: BorderSide(color: Color(0xFFE6E8EA), width: 1.0)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, -1)) ], ), child: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _navItem(Icons.home, "Beranda", _selectedIndex == 0, () { setState(() => _selectedIndex = 0); }), _navItem(Icons.person, "Profil", _selectedIndex == 1, () { setState(() => _selectedIndex = 1); }), ], ), ), ), ); } Widget _navItem( IconData icon, String label, bool isActive, VoidCallback onTap) { return InkWell( onTap: onTap, splashColor: Colors.transparent, highlightColor: Colors.transparent, child: Container( width: 64, padding: const EdgeInsets.symmetric(vertical: 8), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 24, color: isActive ? const Color(0xFF0058BE) : const Color(0xFF424754).withOpacity(0.6), ), const SizedBox(height: 2), Text( label, style: GoogleFonts.inter( fontSize: 10, fontWeight: isActive ? FontWeight.w700 : FontWeight.w500, color: isActive ? const Color(0xFF0058BE) : const Color(0xFF424754).withOpacity(0.6), ), ), ], ), ), ); } } class HomeDriverTab extends StatefulWidget { final Map userData; const HomeDriverTab({super.key, required this.userData}); @override State createState() => _HomeDriverTabState(); } class _HomeDriverTabState extends State with SingleTickerProviderStateMixin { final Color bgLight = const Color(0xFFF7F9FB); final Color surfaceColor = const Color(0xFFFFFFFF); final Color primaryColor = const Color(0xFF0058BE); final Color primaryDark = const Color(0xFF004395); final Color textDark = const Color(0xFF191C1E); final Color textGray = const Color(0xFF424754); final Color borderLight = const Color(0xFFE6E8EA); final Color primary = const Color(0xFF0058BE); final Color onPrimary = const Color(0xFFFFFFFF); final Color primaryContainer = const Color(0xFF2170E4); final Color surfaceContainerLowest = const Color(0xFFFFFFFF); final Color surfaceContainerLow = const Color(0xFFF2F4F6); final Color surfaceContainerHigh = const Color(0xFFE6E8EA); final Color onSurface = const Color(0xFF191C1E); final Color onSurfaceVariant = const Color(0xFF424754); final Color outlineVariant = const Color(0xFFC2C6D6); final Color outline = const Color(0xFF727785); final Color secondaryContainer = const Color(0xFFC3ECD7); final Color onSecondaryContainer = const Color(0xFF476C5B); List tasks = []; Set _sentMessages = {}; bool isLoading = true; late TabController _tabController; final Set _submittingTaskIds = {}; final Set _sendingWhatsAppTaskIds = {}; String formatHarga(dynamic value) { if (value == null) return "0"; String val = value.toString(); RegExp reg = RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'); return val.replaceAllMapped(reg, (Match m) => '${m[1]}.'); } Widget _buildPaymentBadge(Map task) { final payMethod = (task['payment_method'] ?? "").toString().toUpperCase(); final cashRec = num.tryParse(task['cash_received']?.toString() ?? "0") ?? 0; final isUnpaid = payMethod == "BAYAR NANTI" && cashRec == 0; if (isUnpaid) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: const Color(0xFFFFDAD6), borderRadius: BorderRadius.circular(999), border: Border.all(color: const Color(0xFF93000A).withOpacity(0.2)), ), child: Text( "BELUM BAYAR", style: GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.bold, color: const Color(0xFF93000A), ), ), ); } else { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: secondaryContainer, borderRadius: BorderRadius.circular(999), border: Border.all(color: onSecondaryContainer.withOpacity(0.2)), ), child: Text( "LUNAS", style: GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.bold, color: onSecondaryContainer, ), ), ); } } Timer? _refreshTimer; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); _loadSentMessages(); _fetchTasks(); _refreshTimer = Timer.periodic(const Duration(seconds: 3), (_) { _fetchTasks(showLoading: false); }); } @override void dispose() { _refreshTimer?.cancel(); _tabController.dispose(); super.dispose(); } // Mengambil data pesan terkirim dari memori HP Future _loadSentMessages() async { try { final prefs = await SharedPreferences.getInstance(); final List? sentList = prefs.getStringList('sent_wa_messages_v2'); if (sentList != null) { setState(() { _sentMessages = sentList.toSet(); }); } } catch (e) { // ignore: empty_catches } } // Menyimpan data pesan terkirim ke memori HP Future _saveSentMessage(String taskId) async { try { final prefs = await SharedPreferences.getInstance(); setState(() { _sentMessages.add(taskId); }); await prefs.setStringList('sent_wa_messages_v2', _sentMessages.toList()); } catch (e) { // ignore: empty_catches } } Future _fetchTasks({bool showLoading = true}) async { if (!mounted) return; if (showLoading) setState(() => isLoading = true); try { final String? token = widget.userData['access_token']; final response = await http.get( Uri.parse('${AppConfig.baseUrl}/driver/tasks'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', }, ); if (response.statusCode == 200) { final data = json.decode(response.body); if (mounted) { setState(() { tasks = data['data'] ?? []; if (showLoading) isLoading = false; }); } } else { if (mounted && showLoading) setState(() => isLoading = false); } } catch (e) { if (mounted && showLoading) setState(() => isLoading = false); } } void _showSnackBar(String msg, Color bg) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Container( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Icon( bg == const Color(0xFF10B981) ? Icons.check_circle_outline : Icons.error_outline_rounded, color: Colors.white, size: 28, ), const SizedBox(width: 12), Expanded( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( bg == const Color(0xFF10B981) ? "Berhasil" : "Peringatan", style: GoogleFonts.inter( fontWeight: FontWeight.w800, fontSize: 14, color: Colors.white), ), Text( msg, style: GoogleFonts.inter( fontSize: 12, color: Colors.white.withOpacity(0.9), fontWeight: FontWeight.w500), ), ], ), ), ], ), ), behavior: SnackBarBehavior.floating, backgroundColor: bg.withOpacity(0.95), elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), side: BorderSide(color: Colors.white.withOpacity(0.2), width: 1), ), duration: const Duration(seconds: 3), )); } Future _updateTaskStatus(Map task) async { final String taskId = task['type_id'] ?? ''; if (_submittingTaskIds.contains(taskId)) return; setState(() { _submittingTaskIds.add(taskId); }); final String? token = widget.userData['access_token']; final id = task['type_id'].substring(1); final isJemput = task['task_type'] == 'jemput'; final url = isJemput ? '${AppConfig.baseUrl}/pickups/$id/status' : '${AppConfig.baseUrl}/orders/$id/update-status'; try { final response = await http.put( Uri.parse(url), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: json.encode({'status': isJemput ? 'SELESAI' : 'DITERIMA'}), ); if (response.statusCode == 200) { if (mounted) { _showSnackBar( "Tugas berhasil diselesaikan!", const Color(0xFF10B981)); _fetchTasks(); } } } catch (e) { // ignore: empty_catches } finally { if (mounted) { setState(() { _submittingTaskIds.remove(taskId); }); } } } Future _openGoogleMaps(String address, String lat, String lng) async { Uri navUri = (lat.isNotEmpty && lng.isNotEmpty && lat != '0.0') ? Uri.parse('google.navigation:q=$lat,$lng') : Uri.parse('google.navigation:q=${Uri.encodeComponent(address)}'); if (await canLaunchUrl(navUri)) { await launchUrl(navUri); } else { // Fallback jika tidak ada aplikasi Google Maps terinstall Uri webUri = (lat.isNotEmpty && lng.isNotEmpty && lat != '0.0') ? Uri.parse( 'https://www.google.com/maps/dir/?api=1&destination=$lat,$lng') : Uri.parse( 'https://www.google.com/maps/search/?api=1&query=${Uri.encodeComponent(address)}'); if (await canLaunchUrl(webUri)) { await launchUrl(webUri, mode: LaunchMode.externalApplication); } } } Future _sendWhatsApp(String phone, String customerName, String orderNumber, String taskType, String taskId) async { if (_sendingWhatsAppTaskIds.contains(taskId)) return; setState(() { _sendingWhatsAppTaskIds.add(taskId); }); final String? token = widget.userData['access_token']; try { final response = await http.post( Uri.parse('${AppConfig.baseUrl}/send-whatsapp'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: json.encode({ 'phone': phone, 'customer_name': customerName, 'task_type': taskType, }), ); if (response.statusCode == 200) { if (mounted) { _saveSentMessage(taskId); _showSnackBar("Pesan WhatsApp terkirim", const Color(0xFF10B981)); } } } catch (e) { // ignore: empty_catches } finally { if (mounted) { setState(() { _sendingWhatsAppTaskIds.remove(taskId); }); } } } @override Widget build(BuildContext context) { String userName = widget.userData['user']?['name'] ?? "Driver"; List pickupTasks = tasks.where((t) => t['task_type'] == 'jemput').toList(); List deliveryTasks = tasks.where((t) => t['task_type'] == 'antar').toList(); return SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(20, 24, 20, 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Halo, $userName!", style: GoogleFonts.inter( fontSize: 24, fontWeight: FontWeight.w600, color: onSurface, letterSpacing: -0.5)), const SizedBox(height: 4), Text("Siap bertugas hari ini?", style: GoogleFonts.inter( fontSize: 13, color: onSurfaceVariant, fontWeight: FontWeight.w500)), ], ), ], ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Container( height: 48, padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: surfaceContainerHigh, borderRadius: BorderRadius.circular(999), ), child: TabBar( controller: _tabController, indicator: BoxDecoration( borderRadius: BorderRadius.circular(999), color: primary, boxShadow: [ BoxShadow( color: primary.withOpacity(0.2), blurRadius: 12, offset: const Offset(0, 4)) ], ), labelColor: Colors.white, unselectedLabelColor: onSurfaceVariant, labelStyle: GoogleFonts.inter( fontWeight: FontWeight.w500, fontSize: 13), unselectedLabelStyle: GoogleFonts.inter( fontWeight: FontWeight.w500, fontSize: 13), indicatorSize: TabBarIndicatorSize.tab, dividerColor: Colors.transparent, splashBorderRadius: BorderRadius.circular(999), tabs: [ Tab(text: "Pick-up (${pickupTasks.length})"), Tab(text: "Delivery (${deliveryTasks.length})"), ], ), ), ), const SizedBox(height: 16), Expanded( child: isLoading ? const Center(child: CircularProgressIndicator()) : TabBarView( controller: _tabController, children: [ _buildTaskList(pickupTasks, "Tidak ada tugas pick up"), _buildTaskList(deliveryTasks, "Tidak ada tugas antar"), ], ), ), ], ), ); } Widget _buildTaskList(List list, String emptyMessage) { if (list.isEmpty) { return RefreshIndicator( onRefresh: _fetchTasks, child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), child: Container( height: MediaQuery.of(context).size.height * 0.5, width: double.infinity, padding: const EdgeInsets.all(24), alignment: Alignment.center, child: Text(emptyMessage, style: GoogleFonts.inter(fontSize: 13, color: outline)), ), ), ); } return RefreshIndicator( onRefresh: _fetchTasks, child: ListView.separated( padding: const EdgeInsets.fromLTRB(20, 0, 20, 20), itemCount: list.length, separatorBuilder: (_, __) => const SizedBox(height: 12), itemBuilder: (context, index) => _buildTaskCard(list[index]), ), ); } Widget _buildTaskCard(Map task) { bool isJemput = task['task_type'] == 'jemput'; String customerName = task['customer_name'] ?? '-'; String address = task['address'] ?? '-'; String phone = task['phone'] ?? ''; String orderNumber = task['order_number'] ?? ''; if (!orderNumber.startsWith('#') && orderNumber.isNotEmpty) { orderNumber = '#$orderNumber'; } String lat = task['latitude']?.toString() ?? ''; String lng = task['longitude']?.toString() ?? ''; final payMethod = (task['payment_method'] ?? "").toString().toUpperCase(); final cashRec = num.tryParse(task['cash_received']?.toString() ?? "0") ?? 0; final isUnpaid = payMethod == "BAYAR NANTI" && cashRec == 0; return Container( decoration: BoxDecoration( color: surfaceContainerLowest, borderRadius: BorderRadius.circular(16), border: Border.all(color: outlineVariant.withOpacity(0.3)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Column( children: [ Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Header (Order #, Name, Phone, Badges) Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(orderNumber, style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.bold, color: primary, letterSpacing: -0.2)), const SizedBox(height: 2), Text(customerName, style: GoogleFonts.inter( fontSize: 18, fontWeight: FontWeight.w600, color: onSurface)), if (phone.isNotEmpty) ...[ const SizedBox(height: 2), Row( children: [ Icon(Icons.call_rounded, size: 14, color: outline), const SizedBox(width: 6), Text(phone, style: GoogleFonts.inter( fontSize: 11, color: outline)), ], ), ], ], ), ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ if (!isJemput) _buildPaymentBadge(task), if (isJemput) Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 4), decoration: BoxDecoration( color: primary.withOpacity(0.1), borderRadius: BorderRadius.circular(999), border: Border.all(color: primary.withOpacity(0.2)), ), child: Text( "PICK-UP", style: GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.bold, color: primary, ), ), ), if (!isJemput) ...[ const SizedBox(height: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2), decoration: BoxDecoration( color: secondaryContainer.withOpacity(0.5), borderRadius: BorderRadius.circular(6), ), child: Row( children: [ Icon(Icons.local_shipping_rounded, size: 14, color: onSecondaryContainer), const SizedBox(width: 4), Text("Delivery", style: GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.w500, color: onSecondaryContainer)), ], ), ), ], ], ), ], ), const SizedBox(height: 12), // Nota for Delivery if (!isJemput) ...[ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: surfaceContainerLow.withOpacity(0.5), borderRadius: BorderRadius.circular(12), border: Border.all(color: outlineVariant.withOpacity(0.1)), ), child: Column( children: [ // Services if (task['service_name'] != null && task['service_name'].toString().isNotEmpty) ...[ ...task['service_name'] .toString() .split(RegExp(r' \+ |\n')) .map((item) { List parts = item.split('||'); String namePart = parts[0]; String pricePart = parts.length > 1 ? parts[1] : ""; return Padding( padding: const EdgeInsets.only(bottom: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Row( children: [ Icon(Icons.dry_cleaning_rounded, size: 18, color: primary), const SizedBox(width: 8), Expanded( child: Text(namePart, style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: onSurface)), ), ], ), ), if (pricePart.isNotEmpty) Text("Rp ${formatHarga(pricePart)}", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.bold, color: primary)), ], ), ); }), ], const SizedBox(height: 8), Container( padding: const EdgeInsets.only(top: 8), decoration: BoxDecoration( border: Border( top: BorderSide( color: outlineVariant.withOpacity(0.1))), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text("TOTAL TAGIHAN", style: GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.bold, color: outline, letterSpacing: 1.0)), Text("Rp ${formatHarga(task['total_price'])}", style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.bold, color: onSurface)), ], ), ), ], ), ), const SizedBox(height: 8), ], // Address if (isJemput) Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: surfaceContainerLow.withOpacity(0.5), borderRadius: BorderRadius.circular(12), border: Border.all(color: outlineVariant.withOpacity(0.1)), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.location_on_rounded, size: 18, color: primary), const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("ALAMAT PICK UP", style: GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.bold, color: outline, letterSpacing: 0.5)), const SizedBox(height: 2), Text(address, style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: onSurface)), ], ), ), ], ), ) else Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.location_on_rounded, size: 16, color: outline), const SizedBox(width: 6), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("ALAMAT DELIVERY", style: GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.bold, color: outline, letterSpacing: 0.5)), const SizedBox(height: 2), Text(address, style: GoogleFonts.inter( fontSize: 11, color: onSurface, height: 1.2)), ], ), ), ], ), ), // Buttons Map & WA const SizedBox(height: 16), Row( children: [ Expanded( child: InkWell( onTap: () => _openGoogleMaps(address, lat, lng), borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( color: surfaceContainerHigh, borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.map_rounded, size: 18, color: onSurfaceVariant), const SizedBox(width: 8), Text("Rute", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: onSurfaceVariant)), ], ), ), ), ), const SizedBox(width: 12), Expanded( child: InkWell( onTap: (_sentMessages.contains(task['type_id']) || _sendingWhatsAppTaskIds.contains(task['type_id'])) ? null : () => _sendWhatsApp(phone, customerName, orderNumber, task['task_type'], task['type_id']), borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( color: _sentMessages.contains(task['type_id']) ? surfaceContainerHigh : (_sendingWhatsAppTaskIds.contains(task['type_id']) ? secondaryContainer.withOpacity(0.25) : secondaryContainer.withOpacity(0.5)), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (_sendingWhatsAppTaskIds.contains(task['type_id'])) ...[ SizedBox( height: 14, width: 14, child: CircularProgressIndicator( color: onSecondaryContainer, strokeWidth: 2, ), ), const SizedBox(width: 8), Text( "Mengirim...", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: onSecondaryContainer, ), ), ] else ...[ Icon( _sentMessages.contains(task['type_id']) ? Icons.check_circle_rounded : Icons.chat_rounded, size: 18, color: _sentMessages.contains(task['type_id']) ? outline : onSecondaryContainer, ), const SizedBox(width: 8), Text( _sentMessages.contains(task['type_id']) ? "Terkirim" : "Konfirmasi", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: _sentMessages.contains(task['type_id']) ? outline : onSecondaryContainer, ), ), ], ], ), ), ), ), ], ), if (isJemput) ...[ const SizedBox(height: 12), InkWell( onTap: _submittingTaskIds.contains(task['type_id']) ? null : () => _updateTaskStatus(task), borderRadius: BorderRadius.circular(12), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( color: _submittingTaskIds.contains(task['type_id']) ? primary.withOpacity(0.6) : primary, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 2, offset: const Offset(0, 1)) ], ), child: Center( child: _submittingTaskIds.contains(task['type_id']) ? const SizedBox( height: 16, width: 16, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : Text("Finish Pick-up", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w600, color: onPrimary)), ), ), ), ], ], ), ), if (!isJemput) Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: surfaceContainerLowest, border: Border( top: BorderSide(color: outlineVariant.withOpacity(0.1))), borderRadius: const BorderRadius.vertical(bottom: Radius.circular(16)), ), child: InkWell( onTap: _submittingTaskIds.contains(task['type_id']) ? null : () { if (isUnpaid) { Navigator.push( context, MaterialPageRoute( builder: (context) => HomePaymentPage( order: task, userData: widget.userData, ), ), ).then((_) => _fetchTasks()); } else { _updateTaskStatus(task); } }, borderRadius: BorderRadius.circular(12), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 14), decoration: BoxDecoration( color: _submittingTaskIds.contains(task['type_id']) ? primary.withOpacity(0.6) : primary, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 2, offset: const Offset(0, 1)) ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: _submittingTaskIds.contains(task['type_id']) ? [ const SizedBox( height: 16, width: 16, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) ] : [ Text("Finish Delivery", style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w600, color: onPrimary)), const SizedBox(width: 8), Icon(Icons.check_circle_rounded, size: 18, color: onPrimary), ], ), ), ), ), ], ), ); } }