diff --git a/images/manage_users_drawer.png b/images/manage_users_drawer.png new file mode 100644 index 0000000..a49a883 Binary files /dev/null and b/images/manage_users_drawer.png differ diff --git a/lib/common/dashboard.dart b/lib/common/dashboard.dart index 024ce5d..86c0ff2 100644 --- a/lib/common/dashboard.dart +++ b/lib/common/dashboard.dart @@ -7,6 +7,7 @@ import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:supplier_new/common/settings.dart'; +import 'package:supplier_new/common/zoom_image.dart'; import 'package:supplier_new/financials/financial_main_screen.dart'; import 'package:supplier_new/orders/all_orders.dart'; import 'package:supplier_new/orders/order_requests.dart'; @@ -23,6 +24,7 @@ import '../resources/drivers_model.dart'; import '../resources/resources_fleet.dart'; import '../resources/resources_main.dart'; import '../resources/tankers_model.dart'; +import '../users/my_users.dart'; class DashboardScreen extends StatefulWidget { const DashboardScreen({super.key}); @@ -535,15 +537,14 @@ class _DashboardScreenState extends State { 'null'?NetworkImage(AppSettings .profilePictureUrl) as ImageProvider: AssetImage('images/profile_pic.png',), // Your profile image ),*/ - AppSettings.loginType.toString().toLowerCase()=='user'? GestureDetector( onTap: () { - /*Navigator.push( + Navigator.push( context, new MaterialPageRoute( builder: (__) => new ImageZoomPage( imageName: 'Profile', - imageDetails: AppSettings.profilePictureUrl)));*/ + imageDetails: AppSettings.profilePictureUrl))); }, child: Stack( alignment: Alignment.center, // Centers the stack's children @@ -556,18 +557,30 @@ class _DashboardScreenState extends State { width: 100, decoration: BoxDecoration( - color: Colors.transparent, - shape: BoxShape.circle, // Makes the container circular - image: DecorationImage( - image: (AppSettings.profilePictureUrl != - '' && - AppSettings.profilePictureUrl != - 'null') - ? NetworkImage(AppSettings.profilePictureUrl) - as ImageProvider - : AssetImage( - "images/profile_pic.png"), // picked file - fit: BoxFit.cover)), + color: (AppSettings.profilePictureUrl == '' || + AppSettings.profilePictureUrl == 'null') + ? Color(0XFFF3F1FB) + : Colors.transparent, + + shape: BoxShape.circle, + ), + + child: (AppSettings.profilePictureUrl != '' && + AppSettings.profilePictureUrl != 'null') + ? Image.network( + AppSettings.profilePictureUrl, + fit: BoxFit.cover, + height: 100, + width: 100, + ) + : Center( + child: Image.asset( + "images/profile_pic.png", + height: 40, + width: 40, + color: primaryColor, + ), + ), ), ), // Positioned image on top of CircleAvatar @@ -635,29 +648,21 @@ class _DashboardScreenState extends State { ); }); }, - child: Image.asset( - 'images/edit_profile.png', // Ensure the image path is correct - fit: BoxFit.cover, - ), + child: Center( + child: Image.asset( + 'images/edit.png', + width: 14, + height: 14, + fit: BoxFit.contain, + color: primaryColor, + ), + ) ), ), ), ], ), - ):ClipOval( - child: Container( - height: 100, // Ensure the container's height is the same as the profile image - width: 100, - - decoration: BoxDecoration( - color: Colors.transparent, - shape: BoxShape.circle, // Makes the container circular - image: DecorationImage( - image: (AssetImage( - "images/profile_pic.png")), // picked file - fit: BoxFit.contain)), - ), ), SizedBox(height:MediaQuery.of(context).size.height * .016,), Text( @@ -677,7 +682,25 @@ class _DashboardScreenState extends State { ], ),), SizedBox(height:MediaQuery.of(context).size.height * .024,), - + ListTile( + title: Row( + children: [ + Image( + image: const AssetImage('images/manage_users_drawer.png'), + height: 25, + width: 25, + fit: BoxFit.fill,), + SizedBox(width:MediaQuery.of(context).size.width * .04,), + Text('Users', style: fontTextStyle(14,Color(0XFF2A2A2A),FontWeight.w400),), + ], + ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => MyUsers()), + ); + }, + ), ListTile( title: Row( children: [ @@ -768,6 +791,10 @@ class _HomeScreenState extends State { int todaysOrdersCount = 0; int yesterdayPendingOrders = 0; + double todaysRevenue = 0; + double yesterdayRevenue = 0; + String revenueChangeText = "0% from yesterday"; + Color revenueChangeColor = Colors.grey; @override void initState() { @@ -775,6 +802,7 @@ class _HomeScreenState extends State { _fetchDriverCounts(); _fetchTankerCounts(); _fetchTodayOrders(); + _fetchTodayRevenue(); } @@ -846,8 +874,6 @@ class _HomeScreenState extends State { } } - - Future _fetchTodayOrders() async { try { final response = await AppSettings.getAcceptedOrdersFromUsers(); @@ -888,6 +914,123 @@ class _HomeScreenState extends State { } } + Future _fetchTodayRevenue() async { + + try{ + + final response = await AppSettings.getSupplierTransactions(); + + final decoded = jsonDecode(response); + + final List data = decoded["data"] ?? []; + + String todayStr = + DateFormat("dd-MMM-yyyy").format(DateTime.now()); + + String yesterdayStr = + DateFormat("dd-MMM-yyyy") + .format(DateTime.now().subtract(Duration(days: 1))); + + double today = 0; + double yesterday = 0; + + for(var e in data){ + + final orderStatus = + (e["orderStatus"] ?? "").toString().toLowerCase(); + + final date = + (e["dateOfOrder"] ?? "").toString(); + + final price = + double.tryParse(e["price"].toString()) ?? 0; + + final advance = + double.tryParse(e["amount_paid"].toString()) ?? 0; + + double amount = 0; + + if(orderStatus == "completed"){ + amount = price; + } + else if(orderStatus == "advance_paid"){ + amount = advance; + } + else if(orderStatus == "cancelled" || + orderStatus == "refunded"){ + amount = -advance; + } + + if(date == todayStr){ + today += amount; + } + + if(date == yesterdayStr){ + yesterday += amount; + } + + } + + /// percentage calculation + double percent = 0; + + if(yesterday != 0){ + + percent = + ((today - yesterday) / yesterday) * 100; + + } + + String text; + Color color; + + if(percent > 0){ + + text = + "↑ ${percent.abs().toStringAsFixed(0)}% from yesterday"; + + color = Colors.green; + + } + else if(percent < 0){ + + text = + "↓ ${percent.abs().toStringAsFixed(0)}% from yesterday"; + + color = Colors.red; + + } + else{ + + text = "0% from yesterday"; + + color = Colors.grey; + + } + + if(!mounted) return; + + setState(() { + + todaysRevenue = today; + + yesterdayRevenue = yesterday; + + revenueChangeText = text; + + revenueChangeColor = color; + + }); + + } + catch(e){ + + debugPrint("Revenue error $e"); + + } + + } + @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -959,9 +1102,16 @@ class _HomeScreenState extends State { ), DashboardCard( title: "Today's Revenue", - value: "₹24,890", - subtitle: "↑ 8% from yesterday", + value: "₹${todaysRevenue.toStringAsFixed(0)}", + subtitle: revenueChangeText, icon: Icons.currency_rupee, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => FinancialMainScreen()), + ); + }, ), ], ), diff --git a/lib/common/settings.dart b/lib/common/settings.dart index 27924f7..81a72da 100644 --- a/lib/common/settings.dart +++ b/lib/common/settings.dart @@ -153,7 +153,7 @@ class AppSettings{ static String sendSmsUrl = host + 'sendSmstocreatesupplier'; static String resetTokenUrl = host + 'reset_token'; static String verifyPhnUrl = host + 'supplierphone'; - static String uploadPicUrl = host + 'uploads-user'; + static String uploadPicUrl = host + 'uploads_supplier_profile'; static String getOrderRequestsFromUsersUrl = host + 'getuserRequestbookingsforsupplier'; static String acceptOrderRequestsUrl = host + 'request-booking-with-charges'; static String getAcceptedOrdersFromUsersUrl = host + 'getAllTankersBookingdetails'; @@ -192,6 +192,10 @@ class AppSettings{ static String recurringDateActionUrl = host + 'recurring-booking/date-action'; static String cancelTankerBookingUrl = host + 'update-tank-cancel-status'; static String rejectPlanRequestUrl = host + 'rejectplans'; + static String pendingCustomersUrl = host + 'pendingCustomers'; + static String connectedCustomersUrl = host + 'connectedCustomers'; + static String acceptRequestUrl = host +"friend-request/accept"; + static String rejectRequestUrl = host +"friend-request/reject"; static int driverAvailableCount = 0; static int driverOnDeliveryCount = 0; @@ -422,7 +426,7 @@ class AppSettings{ static Future uploadrofileImageHTTPNew(file) async { var request = http.MultipartRequest( 'POST', Uri.parse(uploadPicUrl + '/' + supplierId)); - request.files.add(await http.MultipartFile.fromPath('picture', file.path)); + request.files.add(await http.MultipartFile.fromPath('file', file.path)); var res = await request.send(); var response = await http.Response.fromStream(res); return response.body; @@ -1525,6 +1529,129 @@ class AppSettings{ throw Exception("Failed API call: ${response.body}"); } } + + + static Future getPendingSuppliers() async { + var response = await http.get(Uri.parse(pendingCustomersUrl + '/' + supplierId), + headers: await buildRequestHeaders()); + + if (response.statusCode == 200) { + try { + var _response = json.decode(response.body); + print(_response); + return response.body; + } catch (e) { + // display error toast + return ''; + } + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.get(Uri.parse(pendingCustomersUrl + '/' + supplierId), + headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return response.body; + } else { + return ""; + } + } else { + return ""; + } + } else { + return ""; + } + } + + static Future getConnectedCustomers() async { + var response = await http.get(Uri.parse(connectedCustomersUrl + '/' + supplierId), + headers: await buildRequestHeaders()); + + if (response.statusCode == 200) { + try { + var _response = json.decode(response.body); + print(_response); + return response.body; + } catch (e) { + // display error toast + return ''; + } + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.get(Uri.parse(connectedCustomersUrl + '/' + supplierId), + headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return response.body; + } else { + return ""; + } + } else { + return ""; + } + } else { + return ""; + } + } + + + static Future acceptRequest( payload) async { + var uri = Uri.parse(acceptRequestUrl ); + try { + var response = await http.put(uri, + body: json.encode(payload), headers: await buildRequestHeaders()); + + if (response.statusCode == 200) { + return true; + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.put(uri, + body: json.encode(payload), headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } catch (e) { + print(e); + return false; + } + } + static Future rejectRequest( payload) async { + var uri = Uri.parse(rejectRequestUrl ); + try { + var response = await http.put(uri, + body: json.encode(payload), headers: await buildRequestHeaders()); + + if (response.statusCode == 200) { + return true; + } else if (response.statusCode == 401) { + bool status = await AppSettings.resetToken(); + if (status) { + response = await http.put(uri, + body: json.encode(payload), headers: await buildRequestHeaders()); + if (response.statusCode == 200) { + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } catch (e) { + print(e); + return false; + } + } /*Apis ends here*/ //save data local @@ -1578,7 +1705,7 @@ class AppSettings{ supplierId = await getData('supplierId', 'STRING'); supplierLatitude = await getData('latitude', 'DOUBLE'); supplierLongitude = await getData('longitude', 'DOUBLE'); - //profilePictureUrl = await getData('profile', 'STRING'); + profilePictureUrl = await getData('profile', 'STRING'); // fcmId = await getData('fcmId', 'STRING'); //profileImage=await getData('profile', 'STRING'); getProfile(); @@ -1797,4 +1924,19 @@ class AppSettings{ ); } + static appBarWithoutActions(String title) { + title = title ?? ''; + return AppBar( + backgroundColor: Colors.white, + elevation: 0, + scrolledUnderElevation: 0, + titleSpacing: 0, + title: Text( + title, + style: fontTextStyle(14, Color(0XFF2A2A2A), FontWeight.w500), + ), + iconTheme: IconThemeData(color: Color(0XFF2A2A2A)), + ); + } + } \ No newline at end of file diff --git a/lib/common/splash_screen.dart b/lib/common/splash_screen.dart index cc75f45..62a80b5 100644 --- a/lib/common/splash_screen.dart +++ b/lib/common/splash_screen.dart @@ -7,6 +7,8 @@ import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/login/login.dart'; import 'package:supplier_new/login/starting_screen.dart'; +import '../login/login_signup_screen.dart'; + void main() async{ SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); await Firebase.initializeApp(); @@ -60,7 +62,7 @@ class _SplashScreenState extends State { // Navigate to Login Screen otherwise Navigator.pushReplacement( context, - MaterialPageRoute(builder: (context) => StartingScreen()), + MaterialPageRoute(builder: (context) => LoginSignUpScreen()), ); } } diff --git a/lib/common/zoom_image.dart b/lib/common/zoom_image.dart new file mode 100644 index 0000000..d4a7eb7 --- /dev/null +++ b/lib/common/zoom_image.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:photo_view/photo_view.dart'; +import 'package:supplier_new/common/settings.dart'; + +class ImageZoomPage extends StatefulWidget { + var imageName; + var imageDetails; + ImageZoomPage({this.imageName,this.imageDetails}); + + + @override + State createState() => _ImageZoomPageState(); +} + +class _ImageZoomPageState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppSettings.appBarWithoutActions(widget.imageName), + body: Container( + //width: MediaQuery.of(context).size.width * .10, + //height: MediaQuery.of(context).size.height * .50, + child: PhotoView( + imageProvider: NetworkImage(widget.imageDetails) as ImageProvider, + maxScale: PhotoViewComputedScale.contained * 4.0, + minScale: PhotoViewComputedScale.contained, + initialScale: PhotoViewComputedScale.contained, + basePosition: Alignment.center, + + ) + ), + + ); + } +} diff --git a/lib/financials/financial_main_screen.dart b/lib/financials/financial_main_screen.dart index 2a93967..c7c108f 100644 --- a/lib/financials/financial_main_screen.dart +++ b/lib/financials/financial_main_screen.dart @@ -128,35 +128,85 @@ class _FinancialMainScreenState extends State /// ✅ FETCH TRANSACTIONS API (based on your response) Future fetchTransactions() async { try { - // ⚠️ Use your real method name here + final response = await AppSettings.getSupplierTransactions(); final decoded = jsonDecode(response); final List data = decoded["data"] ?? []; transactions = data.map>((e) { - final orderStatus = (e["orderStatus"] ?? "").toString().toLowerCase(); - final price = (e["price"] ?? "0").toString(); - // completed = credit (+) - // others = debit (-) - final amount = (orderStatus == "completed") ? "+ ₹$price" : "- ₹$price"; + final orderStatus = + (e["orderStatus"] ?? "").toString().toLowerCase(); + + final price = + double.tryParse(e["price"].toString()) ?? 0; + + final advancePaid = + double.tryParse(e["amount_paid"].toString()) ?? 0; + + String amount; + + /// CREDIT CONDITIONS (+) + if (orderStatus == "completed") { + + amount = "+ ₹${price.toStringAsFixed(0)}"; + + } + else if (orderStatus == "advance_paid") { + + /// supplier received advance + amount = "+ ₹${advancePaid.toStringAsFixed(0)}"; + + } + + /// DEBIT CONDITIONS (-) + else if (orderStatus == "refunded" || + orderStatus == "cancelled") { + + amount = "- ₹${advancePaid.toStringAsFixed(0)}"; + + } + + else { - // cancelled = failed UI - final status = (orderStatus == "cancelled") ? "failed" : "success"; + amount = "- ₹${price.toStringAsFixed(0)}"; + + } + + /// UI status + String status; + + if(orderStatus == "cancelled"||orderStatus == "refunded"){ + status = "cancelled"; + }else{ + status = "success"; + } return { - "name": (e["buildingName"] ?? e["customerName"] ?? "Unknown").toString(), + + "name": (e["buildingName"] ?? + e["customerName"] ?? + "Unknown").toString(), + "date": (e["dateOfOrder"] ?? "").toString(), + "amount": amount, + "status": status, - "raw": e, // keep full item if you want details page + + "raw": e, + }; + }).toList(); setState(() => isLoadingTransactions = false); + } catch (e) { + setState(() => isLoadingTransactions = false); + } } diff --git a/lib/login/starting_screen.dart b/lib/login/starting_screen.dart index 5177325..1e38d97 100644 --- a/lib/login/starting_screen.dart +++ b/lib/login/starting_screen.dart @@ -28,7 +28,7 @@ class _StartingScreenState extends State { CircleAvatar(radius: 80, backgroundColor: Color(0XFFF3F1FB)), SizedBox(height: MediaQuery.of(context).size.height * .05), Center( - child: Text("Want to be a supplier on Aquick Tankers?", + child: Text("Want to be a supplier on Aquick Platform?", style: fontTextStyle(16, Color(0XFF343637), FontWeight.w600)), ), SizedBox(height: MediaQuery.of(context).size.height * .04), @@ -56,7 +56,7 @@ class _StartingScreenState extends State { style: fontTextStyle(14, Colors.white, FontWeight.w500), ), )), - SizedBox(height: MediaQuery.of(context).size.height * .012), + /*SizedBox(height: MediaQuery.of(context).size.height * .012), Container( width: double.infinity, height: MediaQuery.of(context).size.height * .06, @@ -81,7 +81,7 @@ class _StartingScreenState extends State { style: fontTextStyle(12, Color(0XFF757575), FontWeight.w500), ), ), - ) + )*/ ], ), )); diff --git a/lib/plans/plan_details.dart b/lib/plans/plan_details.dart index fdfb90f..6c0a19d 100644 --- a/lib/plans/plan_details.dart +++ b/lib/plans/plan_details.dart @@ -286,7 +286,7 @@ class _PlanDetailsState extends State { const SizedBox(height: 24), // BOTTOM BUTTONS - Padding( + /* Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( @@ -342,7 +342,7 @@ class _PlanDetailsState extends State { ), ), - const SizedBox(height: 24), + const SizedBox(height: 24),*/ ], ), ), diff --git a/lib/signup/signup.dart b/lib/signup/signup.dart index b4fb7e3..be4b9e4 100644 --- a/lib/signup/signup.dart +++ b/lib/signup/signup.dart @@ -157,7 +157,31 @@ class _SignUpState extends State { style: fontTextStyle(10, Color(0xFF2D2E30),FontWeight.w600), ), const SizedBox(height: 10), - + Padding( + padding: const EdgeInsets.only(left: 90.0), + child: InkWell( + onTap: () { + getLocationFromMap(); + }, + child: Row( + children: [ + Image.asset( + 'images/maps.png', + width: 20, + height: 20, + color: primaryColor, + ), + const SizedBox(width: 8), + Text( + "Add Location from Maps", + style: fontTextStyle( + 14, const Color(0xFF2D2E30), FontWeight.w500), + ), + ], + ), + ) + ), + const SizedBox(height: 20), _buildTextField('Address Line 1 *', '123 Main St',addressLine1Controller), _buildTextField('Address Line 2(Optional)', 'Area',addressLine2Controller), _buildTextField('City *', 'City',cityController), @@ -165,31 +189,7 @@ class _SignUpState extends State { _buildTextField('ZIP/Postal Code *', '12345',zipController), const SizedBox(height: 10), - Padding( - padding: const EdgeInsets.only(left: 45.0), - child: InkWell( - onTap: () { - getLocationFromMap(); - }, - child: Row( - children: [ - Image.asset( - 'images/maps.png', - width: 20, - height: 20, - color: primaryColor, - ), - const SizedBox(width: 8), - Text( - "Add Location from Maps", - style: fontTextStyle( - 14, const Color(0xFF2D2E30), FontWeight.w500), - ), - ], - ), - ) - ), - const SizedBox(height: 20), + SizedBox( width: double.infinity, child: ElevatedButton( diff --git a/lib/signup/verification_screen.dart b/lib/signup/verification_screen.dart index 42baa7f..1c4740c 100644 --- a/lib/signup/verification_screen.dart +++ b/lib/signup/verification_screen.dart @@ -56,7 +56,7 @@ class _VerificationScreenState extends State { ), ), onPressed: () async { - + SystemNavigator.pop(); }, child: Text( 'Close App', diff --git a/lib/users/connected_users_model.dart b/lib/users/connected_users_model.dart new file mode 100644 index 0000000..a62805b --- /dev/null +++ b/lib/users/connected_users_model.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + + +class ConnectedCustomersModel { + String customer_name = ''; + String customer_phone_number=''; + String customer_building_name=''; + String customer_address=''; + String customer_id=''; + Color text_color=Colors.black; + + + ConnectedCustomersModel(); + + factory ConnectedCustomersModel.fromJson(Map json){ + ConnectedCustomersModel rtvm = new ConnectedCustomersModel(); + + rtvm.customer_name = json['username'] ?? ''; + rtvm.customer_phone_number = json['phone'] ?? ''; + rtvm.customer_building_name = json['buildingName'] ?? ''; + rtvm.customer_address = json['profile']['address1'] ?? ''; + rtvm.customer_id = json['customerId'] ?? ''; + return rtvm; + } + +} \ No newline at end of file diff --git a/lib/users/my_users.dart b/lib/users/my_users.dart new file mode 100644 index 0000000..97cb9b9 --- /dev/null +++ b/lib/users/my_users.dart @@ -0,0 +1,709 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:supplier_new/common/settings.dart'; +import 'package:supplier_new/users/pending_suppliers_model.dart'; + +import 'connected_users_model.dart'; + +class MyUsers extends StatefulWidget { + + var navigationFrom; + + MyUsers({this.navigationFrom}); + + @override + State createState() => _MyUsersState(); + +} + +class _MyUsersState extends State + with TickerProviderStateMixin { + + late TabController _controller; + + bool isPendingLoading=false; + bool isConnectedLoading=false; + bool isRejectedLoading=false; + + List pendingCustomersList=[]; + List connectedCustomersList=[]; + List rejectedCustomersList=[]; + + @override + void initState(){ + + super.initState(); + + _controller=TabController(length:3,vsync:this); + + _controller.addListener(() { + + setState(() {}); + + }); + + getPendingCustomers(); + getConnectedCustomers(); + + } + + Future getPendingCustomers() async { + + setState(() { + isPendingLoading=true; + }); + + try{ + + var response= + await AppSettings.getPendingSuppliers(); + + setState(() { + + pendingCustomersList= + ((jsonDecode(response)['data']) as List) + .map((dynamic model){ + + return PendingSuppliersModel.fromJson(model); + + }).toList(); + + isPendingLoading=false; + + }); + + }catch(e){ + + setState(() { + isPendingLoading=false; + }); + + } + + } + + Future getConnectedCustomers() async { + + setState(() { + + isConnectedLoading=true; + + }); + + try{ + + var response= + await AppSettings.getConnectedCustomers(); + + setState(() { + + connectedCustomersList= + ((jsonDecode(response)['data']) as List) + .map((dynamic model){ + + return ConnectedCustomersModel.fromJson(model); + + }).toList(); + + isConnectedLoading=false; + + }); + + }catch(e){ + + setState(() { + isConnectedLoading=false; + }); + + } + + } + + /*Future getRejectedCustomers() async { + + setState(() { + isRejectedLoading=true; + }); + + try{ + + var response= + await AppSettings.getRejectedCustomers(); + + setState(() { + + rejectedCustomersList= + ((jsonDecode(response)['data']) as List) + .map((dynamic model){ + + return PendingSuppliersModel.fromJson(model); + + }).toList(); + + isRejectedLoading=false; + + }); + + }catch(e){ + + setState(() { + isRejectedLoading=false; + }); + + } + + }*/ + + Widget customerCard(String name,String phone,String address){ + + return Container( + + decoration: BoxDecoration( + + color:Color(0XFFFFFFFF), + + borderRadius:BorderRadius.circular(12), + + border:Border.all( + + color:Colors.grey.shade300, + + width:1, + + ), + + ), + + child:Padding( + + padding:EdgeInsets.fromLTRB(10,10,10,10), + + child:Row( + + children:[ + + CircleAvatar( + + radius:20, + + backgroundColor:Color(0XFFE8F2FF), + + child:Image.asset( + + 'images/profile_user.png', + + width:50, + + height:50, + + ), + + ), + + SizedBox(width:10), + + Expanded( + + child:Column( + + crossAxisAlignment: + CrossAxisAlignment.start, + + children:[ + + Text( + + name, + + style:fontTextStyle( + + 16, + Color(0XFF2D2E30), + FontWeight.w600), + + ), + + SizedBox(height:4), + + Text( + + phone, + + style:fontTextStyle( + + 12, + Color(0XFF515253), + FontWeight.w400), + + ), + + SizedBox(height:4), + + Text( + + address, + + style:fontTextStyle( + + 12, + Color(0XFF515253), + FontWeight.w400), + + ), + + ], + + ), + + ) + + ], + + ), + + ), + + ); + + } + + Widget pendingTab(){ + + if(isPendingLoading){ + + return Center( + + child:CircularProgressIndicator( + + color:primaryColor, + + ), + + ); + + } + + if(pendingCustomersList.isEmpty){ + + return Center( + child:Text("No Pending Customers"), + ); + + } + + return ListView.separated( + + padding:EdgeInsets.all(10), + + itemCount:pendingCustomersList.length, + + separatorBuilder:(c,i)=>SizedBox(height:10), + + itemBuilder:(context,index){ + + return Column( + + children:[ + + customerCard( + + pendingCustomersList[index].customer_name, + + pendingCustomersList[index].customer_phone_number, + + pendingCustomersList[index].customer_address + + ), + + SizedBox(height:8), + + Row( + + children:[ + + Expanded( + + child:GestureDetector( + + onTap:() async { + + var payload={}; + + payload["supplierId"]= + AppSettings.supplierId; + + payload["customerId"]= + pendingCustomersList[index] + .customer_id; + + bool status= + await AppSettings.acceptRequest( + payload); + + if(status){ + + AppSettings.longSuccessToast( + "Accepted"); + + getPendingCustomers(); + getConnectedCustomers(); + + } + + }, + + child:Container( + + decoration:BoxDecoration( + + color:Colors.white, + + border:Border.all( + color:Color(0XFF098603) + ), + + borderRadius: + BorderRadius.circular(24), + + ), + + padding:EdgeInsets.symmetric( + vertical:12), + + alignment:Alignment.center, + + child:Text( + + "Accept", + + style:fontTextStyle( + + 12, + Color(0XFF098603), + FontWeight.w600), + + ), + + ), + + ), + + ), + + SizedBox(width:10), + + Expanded( + + child:GestureDetector( + + onTap:() async { + + var payload={}; + + payload["supplierId"]= + AppSettings.supplierId; + + payload["customerId"]= + pendingCustomersList[index] + .customer_id; + + bool status= + await AppSettings.rejectRequest( + payload); + + if(status){ + + AppSettings.longSuccessToast( + "Rejected"); + + getPendingCustomers(); + //getRejectedCustomers(); + + } + + }, + + child:Container( + + decoration:BoxDecoration( + + color:Colors.white, + + border:Border.all( + color:Colors.red + ), + + borderRadius: + BorderRadius.circular(24), + + ), + + padding:EdgeInsets.symmetric( + vertical:12), + + alignment:Alignment.center, + + child:Text( + + "Reject", + + style:fontTextStyle( + + 12, + Colors.red, + FontWeight.w600), + + ), + + ), + + ), + + ) + + ], + + ) + + ], + + ); + + } + + ); + + } + + Widget connectedTab(){ + + if(isConnectedLoading){ + + return Center( + + child:CircularProgressIndicator( + color:primaryColor), + + ); + + } + + if(connectedCustomersList.isEmpty){ + + return Center( + child:Text("No Connected Customers"), + ); + + } + + return ListView.separated( + + padding:EdgeInsets.all(10), + + itemCount:connectedCustomersList.length, + + separatorBuilder:(c,i)=>SizedBox(height:10), + + itemBuilder:(context,index){ + + return customerCard( + + connectedCustomersList[index].customer_name, + + connectedCustomersList[index] + .customer_phone_number, + + connectedCustomersList[index] + .customer_address + + ); + + } + + ); + + } + + Widget rejectedTab(){ + + if(isRejectedLoading){ + + return Center( + + child:CircularProgressIndicator( + color:primaryColor), + + ); + + } + + if(rejectedCustomersList.isEmpty){ + + return Center( + child:Text("No Rejected Requests"), + ); + + } + + return ListView.separated( + + padding:EdgeInsets.all(10), + + itemCount:rejectedCustomersList.length, + + separatorBuilder:(c,i)=>SizedBox(height:10), + + itemBuilder:(context,index){ + + return customerCard( + + rejectedCustomersList[index].customer_name, + + rejectedCustomersList[index] + .customer_phone_number, + + rejectedCustomersList[index] + .customer_address + + ); + + } + + ); + + } + + @override + Widget build(BuildContext context){ + + return Scaffold( + + backgroundColor:Colors.white, + + appBar:AppBar( + + elevation:0, + + backgroundColor:Colors.white, + + title:Text( + + "Customers", + + style:fontTextStyle( + 14, + Color(0XFF2A2A2A), + FontWeight.w500), + + ), + + bottom:PreferredSize( + + preferredSize:Size.fromHeight(70), + + child:Container( + + margin:EdgeInsets.symmetric( + horizontal:16, + vertical:8), + + padding:EdgeInsets.all(4), + + decoration:BoxDecoration( + + color:Color(0xFFF5F6F6), + + borderRadius: + BorderRadius.circular(23), + + ), + + child:ClipRRect( + + borderRadius: + BorderRadius.circular(19), + + child:TabBar( + + controller:_controller, + + indicator:BoxDecoration(), + + dividerColor:Colors.transparent, + + tabs:List.generate(3,(index){ + + final labels=[ + "Pending", + "Connected", + "Rejected" + ]; + + return Container( + + decoration:BoxDecoration( + + color:_controller.index==index + ?Color(0XFFF5CD47) + :Color(0xFFF5F6F6), + + borderRadius: + BorderRadius.circular(27), + + ), + + child:Tab( + + child:Center( + + child:Text( + + labels[index], + + style:fontTextStyle( + + 12, + Color(0XFF3B3B3B), + FontWeight.w600), + + ), + + ), + + ), + + ); + + }), + + ), + + ), + + ), + + ), + + ), + + body:TabBarView( + + controller:_controller, + + children:[ + + pendingTab(), + + connectedTab(), + + rejectedTab(), + + ], + + ), + + ); + + } + +} \ No newline at end of file diff --git a/lib/users/pending_suppliers_model.dart b/lib/users/pending_suppliers_model.dart new file mode 100644 index 0000000..b933121 --- /dev/null +++ b/lib/users/pending_suppliers_model.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; + + +class PendingSuppliersModel { + String customer_name = ''; + String customer_phone_number=''; + String customer_address=''; + String customer_id=''; + Color text_color=Colors.black; + + + PendingSuppliersModel(); + + factory PendingSuppliersModel.fromJson(Map json){ + PendingSuppliersModel rtvm = new PendingSuppliersModel(); + + rtvm.customer_name = json['username'] ?? ''; + rtvm.customer_phone_number = json['phone'] ?? ''; + rtvm.customer_address = json['profile']['address1'] ?? ''; + rtvm.customer_id = json['customerId'] ?? ''; + return rtvm; + } + +} \ No newline at end of file diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 85a2413..3ccd551 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = @@ -16,4 +17,7 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 62e3ed5..9ce94c4 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_linux flutter_secure_storage_linux + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 9aea0d3..5d1d439 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -14,6 +14,7 @@ import location import package_info_plus import path_provider_foundation import shared_preferences_foundation +import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) @@ -25,4 +26,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 32b9d8e..140341b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -848,6 +848,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + photo_view: + dependency: "direct main" + description: + name: photo_view + sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" + url: "https://pub.dev" + source: hosted + version: "0.15.0" platform: dependency: transitive description: @@ -1037,6 +1045,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79 + url: "https://pub.dev" + source: hosted + version: "6.3.9" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" uuid: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b770bb4..e363d79 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,6 +34,8 @@ dependencies: google_maps_place_picker_mb: ^3.0.2 dropdown_button2: ^2.0.0 table_calendar: ^3.0.2 + photo_view: ^0.15.0 + url_launcher: ^6.1.9 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 41dfcd2..d9d0deb 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -11,6 +11,7 @@ #include #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { FileSelectorWindowsRegisterWithRegistrar( @@ -23,4 +24,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("GeolocatorWindows")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 9c3f356..fb860db 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_secure_storage_windows geolocator_windows permission_handler_windows + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST