import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:bookatanker/common/settings.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:intl/intl.dart'; import 'package:bookatanker/models/supplier_tankers_model.dart'; import 'package:bookatanker/supplier/cart_summary.dart'; class SupplierScreen extends StatefulWidget { var details; SupplierScreen({this.details}); @override State createState() => _SupplierScreenState(); } class _SupplierScreenState extends State { DateTime _focusedDay = DateTime.now(); DateTime? _selectedDay; bool isTankerDataLoading = false; bool isCartDataLoading = false; List tankersList = []; bool isSereverIssue = false; List cart = []; Map localQuantities = {}; Map localTotalPrices = {}; Future getTankers() async { isTankerDataLoading = true; try { var tankerResponse = await AppSettings.getAllTankers(widget.details.supplier_id); setState(() { tankersList = ((jsonDecode(tankerResponse)['data']) as List).map((dynamic model) { return SupplierTankersModel.fromJson(model); }).toList(); isTankerDataLoading = false; }); } catch (e) { setState(() { isTankerDataLoading = false; isSereverIssue = true; }); /* AppSettings.longFailedToast('There is an issue at server side please try after some time'); Navigator.pop(context);*/ } } Future getCart() async { isCartDataLoading = true; try { var tankerResponse = await AppSettings.getCartItems(); setState(() { cart = ((jsonDecode(tankerResponse)['data']['items'])); isCartDataLoading = false; }); } catch (e) { setState(() { isCartDataLoading = false; isSereverIssue = true; }); /* AppSettings.longFailedToast('There is an issue at server side please try after some time'); Navigator.pop(context);*/ } } @override void initState() { super.initState(); _selectedDay = _focusedDay; getTankers(); getCart(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Color(0XFFFFFFFF), appBar:AppSettings.SupplierAppBar('Place Order',context), body: Padding( padding: EdgeInsets.fromLTRB(12, 8, 12, 8), child: ListView( children: [ // Supplier Card Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), elevation: 2, color: Colors.white, child: Column( children: [ Padding( padding: EdgeInsets.fromLTRB(8, 8, 8, 8), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Visibility( visible: true, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Visibility( visible: widget.details.supplier_name != '', child: Text( widget.details.supplier_name.toString(), style: fontTextStyle( 16, Color(0XFF2D2E30), FontWeight.w600), ), ), Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Image.asset( 'images/star.png', fit: BoxFit.cover, width: 16, // Match the diameter of the CircleAvatar height: 16, ), Visibility( visible: true, child: Text( '4.2 (20K+ Ratings)', style: fontTextStyle(9, Color(0XFF515253), FontWeight.w400), ), ), ], ) ], ), ), Visibility( visible: true, child: Text( 'Drinking | Bore Water', style: fontTextStyle( 12, Color(0XFF4692FD), FontWeight.w500), ), ), Visibility( visible: true, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.details.displayAddress + ' ' + widget.details.distanceInMeters .toString() + ' Km', style: fontTextStyle(12, Color(0XFF515253), FontWeight.w400)), Image.asset( 'images/heart_outline.png', fit: BoxFit.cover, width: 16, // Match the diameter of the CircleAvatar height: 16, ), ], ), ), ], ), ), Padding( padding: EdgeInsets.zero, child: Container( width: double .infinity, // makes it expand within the Card's width decoration: BoxDecoration( borderRadius: BorderRadius.vertical( bottom: Radius.circular(12), ), // match Card border gradient: LinearGradient( colors: [ Color(0xFFFFE8A3), Color(0xFFFFF8DF), Color(0xFFFFFFFF), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), padding: EdgeInsets.symmetric(vertical: 12), alignment: Alignment.center, child: Padding( padding: EdgeInsets.fromLTRB(12, 0, 12, 0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Image.asset( 'images/ring.png', fit: BoxFit.cover, width: 16, // Match the diameter of the CircleAvatar height: 16, ), Text('Best water quality', style: fontTextStyle( 10, Color(0XFF2D2E30), FontWeight.w400)), ], ), Row( children: [ Image.asset( 'images/ring.png', fit: BoxFit.cover, width: 16, // Match the diameter of the CircleAvatar height: 16, ), Text('Steel casing tankers', style: fontTextStyle( 10, Color(0XFF2D2E30), FontWeight.w400)), ], ) ], ), )), ), ], )), Card( color: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.fromLTRB(12, 12, 12, 0), child: Column( children: [ // Header Row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( DateFormat.yMMM().format(_focusedDay), style: fontTextStyle(12, Color(0XFF646566), FontWeight.w600), ), Image.asset( 'images/calender.png', fit: BoxFit.cover, width: 16, // Match the diameter of the CircleAvatar height: 16, ), ], ), Divider( color: Colors.grey.shade300, ), // Weekly Calendar TableCalendar( focusedDay: _focusedDay, firstDay: DateTime.now(), lastDay: DateTime.now().add(Duration(days: 15)), calendarFormat: CalendarFormat.week, startingDayOfWeek: StartingDayOfWeek.sunday, availableCalendarFormats: const { CalendarFormat.week: 'Week', }, selectedDayPredicate: (day) { return isSameDay(_selectedDay, day); }, onDaySelected: (selectedDay, focusedDay) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; }); }, headerVisible: false, calendarStyle: CalendarStyle( todayDecoration: BoxDecoration(), // No box for today todayTextStyle:fontTextStyle(12, Color(0XFF1D7AFC), FontWeight.w400), selectedDecoration: BoxDecoration( color: Color(0XFF1D7AFC), shape: BoxShape.circle, ), selectedTextStyle: fontTextStyle(12, Color(0XFFFFFFFF), FontWeight.w400), weekendTextStyle: TextStyle(color: Colors.black), defaultTextStyle: TextStyle(color: Colors.black), outsideDaysVisible: false, ), daysOfWeekStyle: DaysOfWeekStyle( weekdayStyle: fontTextStyle(12, Color(0XFF343637), FontWeight.w400), weekendStyle: fontTextStyle(12, Color(0XFF343637), FontWeight.w400), ), ), ], ), )), SizedBox(height: MediaQuery.of(context).size.height * .016), Padding(padding: EdgeInsets.fromLTRB(6, 0, 6, 0), child: Container( width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Color(0XFFFCF0E7), borderRadius: BorderRadius.circular(6), border: Border.all ( color: Color(0XFFEFA168)), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Image.asset( 'images/warning.png', fit: BoxFit.cover, width: 22, // Match the diameter of the CircleAvatar height: 22, ), SizedBox(width: MediaQuery.of(context).size.width * .020), Expanded(child: Text( 'The prices shown below are NOT inclusive of the transport charges. Transport charges are calculated based on the distance between the sourcing location and the delivery location.', style: fontTextStyle( 10, Color(0XFF444444), FontWeight.w400), ),) ], ) ),), SizedBox(height: MediaQuery.of(context).size.height * .016), // Supply Locations Text('SUPPLY LOCATIONS', style: fontTextStyle( 12, Color(0XFF646566), FontWeight.w400),), SizedBox(height: MediaQuery.of(context).size.height * .016), Card( elevation: 2, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), color: Color(0XFFFFFFFF), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ...[ {'name': 'Gandipet', 'type': 'Drinking water', 'km': '4.5 Km'}, {'name': 'Nizampet', 'type': 'Drinking water', 'km': '7.3 Km'}, {'name': 'Secunderabad', 'type': 'Bore water', 'km': '12.4 Km'}, ].map((location) => Padding( padding: const EdgeInsets.only(bottom: 12.0), child: ListBody( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(location['name']!, style: fontTextStyle(12, Color(0XFF2D2E30), FontWeight.w500),), Text(location['km']!,style: fontTextStyle(10, Color(0XFF2D2E30), FontWeight.w500),), ], ), Text(location['type']!, style: fontTextStyle(10, Color(0XFF515253), FontWeight.w400),), ], ), )), ], ), ), ), // Tankers SizedBox(height: MediaQuery.of(context).size.height * .016), Text('TANKERS', style: fontTextStyle( 12, Color(0XFF646566), FontWeight.w400),), SizedBox(height: MediaQuery.of(context).size.height * .016), GridView.builder( padding: const EdgeInsets.all(0), itemCount: tankersList.length, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 12, crossAxisSpacing: 12, childAspectRatio: 1.6, ), itemBuilder: (context, index) { final tanker = tankersList[index]; final isAvailable = tankersList[index].status == 'Available'; final isEnabled =tankersList[index].enabled; return Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), elevation: 2, color: Color(0XFFFFFFFF), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( tankersList[index].capacity+' Litres', style: fontTextStyle(12, Color(0XFF2D2E30), FontWeight.w500), ), Text( '\u20B9 '+AppSettings.formDouble(tankersList[index].price), style: fontTextStyle(12, Color(0XFF515253), FontWeight.w400), ), ], ), Text( tankersList[index].type_of_water, style: fontTextStyle(12, Color(0XFF515253), FontWeight.w400), ), Expanded(child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( borderRadius: BorderRadius.circular(6), border: Border.all( color: isAvailable ? Color(0XFF098603) : Colors.grey,), ), child: Text( tankersList[index].status, style: fontTextStyle( 12, isAvailable ? Color(0XFF098603) : Colors.grey, FontWeight.w500), ), ), ElevatedButton( onPressed: isEnabled ? () async { AppSettings.preLoaderDialog(context); final product = tankersList[index]; final productId = product.id; final name = product.tanker_name; // Convert price safely from string like "1,000" final priceString = product.price; final unitPrice = int.parse(priceString.replaceAll(',', '')); // Get current quantity, or 0 if not added yet int currentQuantity = localQuantities[productId] ?? 0; int newQuantity = currentQuantity + 1; // Calculate total price for UI use (unitPrice * quantity) int totalPrice = unitPrice * newQuantity; // Prepare payload to send unit price and quantity only final payload = { "productId": productId, "name": name, "quantity": newQuantity, "price": unitPrice, // unit price ONLY }; try { final response = await http.post( Uri.parse('${AppSettings.host}cart/${AppSettings.customerId}/add'), headers: await AppSettings.buildRequestHeaders(), body: jsonEncode(payload), ); if (response.statusCode == 200 || response.statusCode == 201) { setState(() { Navigator.of(context, rootNavigator: true).pop(); // Update local tracking maps localQuantities[productId] = newQuantity; localTotalPrices[productId] = totalPrice; // Update or add the cart list entry int existingIndex = cart.indexWhere((item) => item['productId'] == productId); if (existingIndex != -1) { cart[existingIndex]['quantity'] = newQuantity; cart[existingIndex]['price'] = unitPrice; // unit price cart[existingIndex]['total'] = totalPrice; // total price for UI } else { cart.add({ "productId": productId, "name": name, "quantity": newQuantity, "price": unitPrice, "total": totalPrice, }); } }); // Optional: refresh cart from server if you want await getCart(); } else { Navigator.of(context, rootNavigator: true).pop(); print('Failed to add to cart: ${response.body}'); } } catch (e) { Navigator.of(context, rootNavigator: true).pop(); print('Error adding to cart: $e'); } } : null, style: ElevatedButton.styleFrom( backgroundColor: isEnabled ? primaryColor : Colors.grey[300], foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), minimumSize: Size(48, 32), padding: EdgeInsets.zero, ), child: Text( 'Add', style: fontTextStyle(12, Color(0XFFFFFFFF), FontWeight.w400), ), ), ], )) ], ), ), ); }, ), ], ), ), bottomNavigationBar: cart.isNotEmpty ? Padding( padding: EdgeInsets.all(0), child: Container( height: 56, width: double.infinity, decoration: BoxDecoration( color: Color(0XFFF5CD47), borderRadius: BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12), ), ), padding: EdgeInsets.symmetric(horizontal: 24), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Order updated", style: fontTextStyle(12, Color(0XFF232527), FontWeight.w500), ), GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => CartSummary(details: cart,supplierDetails: widget.details,)), ); }, child: Row( children: [ Text( "View summary", style: fontTextStyle(12, Color(0XFF232527), FontWeight.w500), ), Image.asset( 'images/arrow-right.png', fit: BoxFit.cover, width: 20, // Match the diameter of the CircleAvatar height: 20, color: Color(0XFF343637), ), ], ), ), ], ), ), ) : null, ); } }