TKK_E32230801/laundry_mobile/lib/driver/beranda.dart

1056 lines
40 KiB
Dart

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<String, dynamic> userData;
const BerandaPage({super.key, required this.userData});
@override
State<BerandaPage> createState() => _BerandaPageState();
}
class _BerandaPageState extends State<BerandaPage> {
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<String, dynamic> userData;
const HomeDriverTab({super.key, required this.userData});
@override
State<HomeDriverTab> createState() => _HomeDriverTabState();
}
class _HomeDriverTabState extends State<HomeDriverTab>
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<dynamic> tasks = [];
Set<String> _sentMessages = {};
bool isLoading = true;
late TabController _tabController;
final Set<String> _submittingTaskIds = {};
final Set<String> _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<String, dynamic> 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<void> _loadSentMessages() async {
try {
final prefs = await SharedPreferences.getInstance();
final List<String>? 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<void> _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<void> _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<void> _updateTaskStatus(Map<String, dynamic> 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<void> _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<void> _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<dynamic> pickupTasks =
tasks.where((t) => t['task_type'] == 'jemput').toList();
List<dynamic> 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<dynamic> 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<String, dynamic> 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<String> 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),
],
),
),
),
),
],
),
);
}
}