From ac734007af0e00ad322d547bafd047f864491560 Mon Sep 17 00:00:00 2001 From: gitadmin Date: Thu, 6 Nov 2025 12:31:06 +0530 Subject: [PATCH] source and service location changes --- lib/profile/employees.dart | 6 +- lib/profile/fleet.dart | 28 +- lib/profile/service_location.dart | 577 ++++++++++++++++-------------- lib/profile/source_location.dart | 27 +- 4 files changed, 346 insertions(+), 292 deletions(-) diff --git a/lib/profile/employees.dart b/lib/profile/employees.dart index 99c7d2d..1fa0bb4 100644 --- a/lib/profile/employees.dart +++ b/lib/profile/employees.dart @@ -498,8 +498,10 @@ class _FleetEmployeesState extends State { ElevatedButton( onPressed: _addDriver, style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0D3771), - foregroundColor: Colors.white), + backgroundColor: const Color(0xFF8270DB), + foregroundColor: Colors.white, + minimumSize: const Size(343, 41), // Width & Height + padding: const EdgeInsets.fromLTRB(24, 12, 24, 12),), child: const Text("Add Driver"), ), ], diff --git a/lib/profile/fleet.dart b/lib/profile/fleet.dart index e8f0a99..27cea15 100644 --- a/lib/profile/fleet.dart +++ b/lib/profile/fleet.dart @@ -487,14 +487,26 @@ class _AddTankerFormState extends State { onTap: _pickInsuranceDate, ), ), - const SizedBox(height: 16), - ElevatedButton( - onPressed: _addTanker, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF0D3771), - foregroundColor: Colors.white), - child: const Text("Add Tanker"), - ), + SizedBox( + child: ElevatedButton.icon( + onPressed: _addTanker, + label: Text( + "Add Tanker", + style: fontTextStyle(14, Colors.white, FontWeight.w600), + ), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF8270DB), + foregroundColor: Colors.white, + minimumSize: const Size(343, 41), // Width & Height + padding: const EdgeInsets.fromLTRB(24, 12, 24, 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24), + ), + elevation: 0, // Optional: flat style per modern UI + ), + ), + ) + ], ), ), diff --git a/lib/profile/service_location.dart b/lib/profile/service_location.dart index c232d51..deb10f8 100644 --- a/lib/profile/service_location.dart +++ b/lib/profile/service_location.dart @@ -1,5 +1,7 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:supplier_new/common/settings.dart'; +import '../resources/source_loctaions_model.dart'; void main() => runApp(const MaterialApp(home: ServiceLocation())); @@ -16,6 +18,49 @@ class _ServiceLocationState extends State { final TextEditingController _radiusController = TextEditingController(text: "10"); bool _customizeEachSource = false; + bool isLoading = false; + int currentStep = 3; + List sourceLocationsList = []; + + + final List _services = [ + "24/7 Emergency services", + "Scheduled water deliveries", + "Bulk water deliveries", + "Long-term water delivery plans", + "Industrial/Commercial water deliveries" + ]; + final Set _selectedServices = {}; + + + final Map _expandedMap = {}; + + @override + void initState() { + super.initState(); + _fetchSources(); + } + + Future _fetchSources() async { + setState(() => isLoading = true); + try { + final response = await AppSettings.getSourceLoctaions(); + final data = (jsonDecode(response)['data'] as List) + .map((e) => SourceLocationsModel.fromJson(e)) + .toList(); + if (!mounted) return; + setState(() { + sourceLocationsList = data; + isLoading = false; + for (var i = 0; i < data.length; i++) { + _expandedMap[i] = false; + } + }); + } catch (e) { + debugPrint("⚠️ Error fetching source locations: $e"); + setState(() => isLoading = false); + } + } @override Widget build(BuildContext context) { @@ -25,323 +70,325 @@ class _ServiceLocationState extends State { backgroundColor: Colors.white, surfaceTintColor: Colors.transparent, elevation: 0, - scrolledUnderElevation: 0, title: const Text("Complete Profile"), - actions: [ - IconButton( - splashRadius: 20, - icon: const Image( - image: AssetImage('images/calendar_appbar.png'), - width: 22, - height: 22, - ), - onPressed: () {}, - ), - IconButton( - splashRadius: 20, - icon: Image.asset('images/notification_appbar.png', - width: 22, height: 22), - onPressed: () {}, - ), - ], ), body: SafeArea( - child: Form( - key: _formKey, - child: ListView( - padding: const EdgeInsets.fromLTRB(20, 10, 20, 24), - children: [ - // Step indicator - Text("Step 3/5", - style: - fontTextStyle(16, const Color(0xFFC3C4C4), FontWeight.w500)), - const SizedBox(height: 16), - Row( - children: List.generate(5, (index) { - final isFilled = index < 3; - return Expanded( - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 2), - height: 5, - decoration: BoxDecoration( - color: isFilled - ? const Color(0xFF0D3771) - : const Color(0xFFE6E6E6), - borderRadius: BorderRadius.circular(2), - ), + child: isLoading + ? const Center(child: CircularProgressIndicator()) + : Form( + key: _formKey, + child: ListView( + padding: const EdgeInsets.fromLTRB(20, 10, 20, 24), + children: [ + Text("Step $currentStep/5", + style: fontTextStyle(16, Color(0xFFC3C4C4), FontWeight.w500)), + const SizedBox(height: 16), + Row( + children: List.generate(5, (index) { + final isFilled = index < currentStep; + return Expanded( + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 2), + height: 5, + decoration: BoxDecoration( + color: isFilled + ? const Color(0xFF0D3771) + : const Color(0xFFE6E6E6), + borderRadius: BorderRadius.circular(2), + ), + ), + ); + }), ), - ); - }), - ), - const SizedBox(height: 16), - Text("SOURCE LOCATION", - style: - fontTextStyle(20, const Color(0xFF515253), FontWeight.w600)), - const SizedBox(height: 8), - Align( - alignment: Alignment.centerLeft, - child: Image.asset('images/marker-pin.png', width: 24, height: 24), - ), - const SizedBox(height: 12), - Text( - "Define where you want to provide delivery services", - style: - fontTextStyle(14, const Color(0xFF939495), FontWeight.w500), - ), - const SizedBox(height: 6), + const SizedBox(height: 16), - // Radio Buttons - RadioListTile( - value: 'business', - groupValue: _deliveryFrom, - onChanged: (value) => - setState(() => _deliveryFrom = value ?? 'business'), - title: Text("From Business Location", - style: fontTextStyle( - 14, const Color(0xFF2D2E30), FontWeight.w500)), - dense: true, - contentPadding: EdgeInsets.zero, - visualDensity: - const VisualDensity(horizontal: 0, vertical: -3), - ), - RadioListTile( - value: 'source', - groupValue: _deliveryFrom, - onChanged: (value) => - setState(() => _deliveryFrom = value ?? 'source'), - title: Text("From Source Locations", - style: fontTextStyle( - 14, const Color(0xFF2D2E30), FontWeight.w500)), - dense: true, - contentPadding: EdgeInsets.zero, - visualDensity: - const VisualDensity(horizontal: 0, vertical: -3), - ), - - const SizedBox(height: 12), - - // ✅ Business Location Section - Visibility( - visible: _deliveryFrom == 'business', - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Delivery Radius (in Kms) *", - style: fontTextStyle( - 14, const Color(0xFF2D2E30), FontWeight.w500)), - const SizedBox(height: 6), - TextFormField( - controller: _radiusController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - hintText: "Enter radius in kms", - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 12), - ), + Text("SERVICE LOCATIONS", + style: fontTextStyle(20, Color(0xFF515253), FontWeight.w600)), + const SizedBox(height: 16), + Align( + alignment: Alignment.centerLeft, + child: Image.asset('images/marker-pin.png', + width: 24, height: 24), ), - - const SizedBox(height: 12), - Container( - width: double.infinity, - height: 160, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('images/google_maps.png'), - fit: BoxFit.contain, - ), - ), + const SizedBox(height: 16), + Text( + "Define where you want to provide delivery services", + style: fontTextStyle(14, Color(0xFF939495), FontWeight.w500), ), - ], - ), - ), + const SizedBox(height: 16), - // ✅ Source Location Customization Section - Visibility( - visible: _deliveryFrom == 'source', - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 12), - - // 🔹 Checkbox toggle - Row( - children: [ - Checkbox( - value: _customizeEachSource, - onChanged: (val) => - setState(() => _customizeEachSource = val ?? false), - ), - const SizedBox(width: 6), - Expanded( - child: Text( - "Customize for each source location", - style: fontTextStyle( - 14, const Color(0xFF2D2E30), FontWeight.w500), - ), - ), - ], + RadioListTile( + value: 'business', + groupValue: _deliveryFrom, + onChanged: (value) => + setState(() => _deliveryFrom = value ?? 'business'), + title: Text("From Business Location", + style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400)), + dense: true, + contentPadding: EdgeInsets.zero, + visualDensity: + const VisualDensity(horizontal: 0, vertical: -3), + ), + RadioListTile( + value: 'source', + groupValue: _deliveryFrom, + onChanged: (value) => + setState(() => _deliveryFrom = value ?? 'source'), + title: Text("From Source Locations", + style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400)), + dense: true, + contentPadding: EdgeInsets.zero, + visualDensity: + const VisualDensity(horizontal: 0, vertical: -3), ), - const SizedBox(height: 12), + const SizedBox(height: 16), + - // 🔹 Only the list hides/shows Visibility( - visible: _customizeEachSource, + visible: _deliveryFrom == 'business', child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - _SectionHeaderBar(title: "SOURCE LOCATION #1"), - const SizedBox(height: 12), - Text( - "Delivery Radius (in Kms) *", - style: fontTextStyle( - 14, const Color(0xFF2D2E30), FontWeight.w500), - ), - const SizedBox(height: 6), + Text("Delivery Radius (in Kms) *", + style: fontTextStyle(12, Color(0xFF2F3036), FontWeight.w600)), + const SizedBox(height: 16), TextFormField( - controller: TextEditingController(text: "10"), + controller: _radiusController, keyboardType: TextInputType.number, decoration: InputDecoration( hintText: "Enter radius in kms", + hintStyle: fontTextStyle(14, Color(0xFF939495), FontWeight.w400), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), - contentPadding: - const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 12), ), ), - const SizedBox(height: 12), - _SectionHeaderBar(title: "SOURCE LOCATION #2"), - const SizedBox(height: 12), - Text( - "Delivery Radius (in Kms) *", - style: fontTextStyle( - 14, const Color(0xFF2D2E30), FontWeight.w500), + const SizedBox(height: 16), + Container( + width: double.infinity, + height: 160, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/google_maps.png'), + fit: BoxFit.contain, + ), + ), ), - const SizedBox(height: 6), + ], + ), + ), + + // ✅ Source Location Customization Section + Visibility( + visible: _deliveryFrom == 'source', + child: Column( + + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Delivery Radius (in Kms) *", + style: fontTextStyle(12, Color(0xFF2F3036), FontWeight.w600)), + const SizedBox(height: 16), TextFormField( - controller: TextEditingController(text: "8"), + controller: _radiusController, keyboardType: TextInputType.number, decoration: InputDecoration( hintText: "Enter radius in kms", + hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), - contentPadding: - const EdgeInsets.symmetric(horizontal: 12, vertical: 12), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 12), ), ), + const SizedBox(height: 16), + Row( + children: [ + Checkbox( + value: _customizeEachSource, + onChanged: (val) => setState( + () => _customizeEachSource = val ?? false), + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity( + horizontal: -4, vertical: -4), + ), + const SizedBox(width: 6), + + Expanded( + child: Text( + "Customize for each source location", + style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400), + ), + ), + ], + ), const SizedBox(height: 12), + + // 🔹 Show all source locations when checkbox checked + if (_customizeEachSource) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: sourceLocationsList.isEmpty + ? [ + const Text("No source locations available"), + ] + : List.generate(sourceLocationsList.length, (index) { + final d = sourceLocationsList[index]; + return StatefulBuilder( + builder: (context, setInner) { + // ✅ Always read from map dynamically (not fixed final variable) + final isExpanded = _expandedMap[index] ?? false; + + return Container( + margin: const EdgeInsets.only(bottom: 8), + decoration: BoxDecoration( + color: const Color(0xFFF7F7F7), + border: Border.all(color: const Color(0xFFE5E5E5)), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + children: [ + ListTile( + dense: true, + contentPadding: EdgeInsets.zero, + minVerticalPadding: 0, + visualDensity: const VisualDensity(vertical: -4, horizontal: 0), + title: Text( + d.source_name ?? 'Unnamed location', + style: fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w600), + ), + trailing: IconButton( + icon: Image.asset( + isExpanded + ? 'images/arrow-up.png' + : 'images/downarrow.png', + width: 18, + height: 18, + ), + onPressed: () { + setInner(() { + _expandedMap[index] = !isExpanded; + }); + }, + ), + ), + if (isExpanded) + Container( + margin: const EdgeInsets.only(left: 10, right: 10, bottom: 6), + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: const Color(0xFFE5E5E5)), + ), + child: Text( + "Address: ${d.address ?? 'N/A'}", + style: fontTextStyle(12, const Color(0xFF646566), FontWeight.w400), + ), + ), + ], + ), + ); + }, + ); + }), + ), + + const SizedBox(height: 16), + Container( + width: double.infinity, + height: 160, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/google_maps.png'), + fit: BoxFit.contain, + ), + ), + ), ], ), ), - // 🔹 Map always visible - Container( + const SizedBox(height: 24), + Text("Types of Services", + style: fontTextStyle(16, Color(0xFF2D2E30), FontWeight.w600)), + const SizedBox(height: 12), + Text( + "Define what type of services you would wish to provide", + style: fontTextStyle(14, Color(0xFF939495), FontWeight.w500)), + + const SizedBox(height: 16), + ..._services + .map((service) => _serviceItem(service)) + .toList(), + const SizedBox(height: 24), + SizedBox( width: double.infinity, - height: 160, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('images/google_maps.png'), - fit: BoxFit.contain, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF8270DB), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24)), ), + onPressed: () { + final selected = _selectedServices.isEmpty + ? "No services selected" + : _selectedServices.join(", "); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Saved successfully for ${_deliveryFrom == 'business' ? 'Business Location' : 'Source Locations'}\nSelected: $selected"), + ), + ); + }, + child: Text("Save & Continue", + style: fontTextStyle(14, Color(0xFFFFFFFF), FontWeight.w400)), ), ), ], ), ), - - - - const SizedBox(height: 24), - Text("Types of Services", - style: fontTextStyle( - 16, const Color(0xFF2D2E30), FontWeight.w600)), - const SizedBox(height: 12), - Text("Define what type of services you would wish to provide", - style: - fontTextStyle(14, const Color(0xFF939495), FontWeight.w500)), - const SizedBox(height: 20), - - _serviceItem("24/7 Emergency services"), - _serviceItem("Scheduled water deliveries"), - _serviceItem("Bulk water deliveries"), - _serviceItem("Long-term water delivery plans"), - _serviceItem("Industrial/Commercial water deliveries"), - - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF8270DB), - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24)), - ), - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - "Saved successfully for ${_deliveryFrom == 'business' ? 'Business Location' : 'Source Locations'}"), - ), - ); - }, - child: Text("Save & Continue", - style: fontTextStyle(14, Colors.white, FontWeight.w400)), - ), - ), - ], - ), - ), ), ); } - Widget _serviceItem(String label) => Padding( - padding: const EdgeInsets.only(bottom: 12), - child: Row( - children: [ - const Icon(Icons.check_box_outline_blank, - size: 20, color: Color(0xFF939495)), - const SizedBox(width: 8), - Text(label, - style: - fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400)), - ], - ), - ); -} - -class _SectionHeaderBar extends StatelessWidget { - final String title; - - const _SectionHeaderBar({required this.title, super.key}); - - @override - Widget build(BuildContext context) { - return Container( - decoration: BoxDecoration( - color: const Color(0xFFEEEEEE), - border: Border.all(color: const Color(0xFFE5E7EB), width: 1), - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.04), - blurRadius: 6, - offset: const Offset(0, 2), - ), - ], + // ✅ Service item + Widget _serviceItem(String label) { + final bool selected = _selectedServices.contains(label); + return GestureDetector( + onTap: () { + setState(() { + if (selected) { + _selectedServices.remove(label); + } else { + _selectedServices.add(label); + } + }); + }, + child: Container( + margin: const EdgeInsets.only(bottom: 8), + child: Row( + children: [ + Icon( + selected ? Icons.check_box : Icons.check_box_outline_blank, + color: selected ? Color(0xFF8270DB) : Color(0xFF939495), + size: 20, + ), + const SizedBox(width: 8), + Expanded( + child: Text(label, style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400), + ), + ), + ], + ), ), - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - child: Text(title, - style: - fontTextStyle(10, const Color(0xFF2D2E30), FontWeight.w600)), ); } } diff --git a/lib/profile/source_location.dart b/lib/profile/source_location.dart index 059850b..b0aef3e 100644 --- a/lib/profile/source_location.dart +++ b/lib/profile/source_location.dart @@ -162,8 +162,7 @@ class _SourceLocationState extends State { Center( child: Text( "Add Source Location", - style: fontTextStyle( - 16, const Color(0xFF2D2E30), FontWeight.w600), + style: fontTextStyle(16, Color(0xFF2D2E30), FontWeight.w600), ), ), const SizedBox(height: 20), @@ -304,7 +303,7 @@ class _SourceLocationState extends State { ), ), ), - const SizedBox(height: 12), + const SizedBox(height: 16), ], ), ), @@ -401,8 +400,7 @@ class _SourceLocationState extends State { padding: const EdgeInsets.fromLTRB(20, 10, 20, 24), children: [ Text("Step $currentStep/5", - style: fontTextStyle( - 16, const Color(0xFFC3C4C4), FontWeight.w500)), + style: fontTextStyle(16, Color(0xFFC3C4C4), FontWeight.w500)), const SizedBox(height: 16), Row( children: List.generate(5, (index) { @@ -420,18 +418,16 @@ class _SourceLocationState extends State { }), ), const SizedBox(height: 16), - Text("SOURCE LOCATION", - style: fontTextStyle( - 20, const Color(0xFF515253), FontWeight.w600)), - const SizedBox(height: 16), + Text("SOURCE LOCATIONS", + style: fontTextStyle(20, Color(0xFF515253), FontWeight.w600)), + const SizedBox(height: 6), Align( alignment: Alignment.centerLeft, child: Image.asset('images/truck.png', width: 24, height: 24), ), const SizedBox(height: 16), Text("Add your source location", - style: fontTextStyle( - 14, const Color(0xFF939495), FontWeight.w500)), + style: fontTextStyle(14, Color(0xFF939495), FontWeight.w500)), const SizedBox(height: 16), // List of saved locations @@ -496,10 +492,7 @@ class _SourceLocationState extends State { ), child: Text( "Address: ${d.address ?? 'N/A'}", - style: fontTextStyle( - 12, - const Color(0xFF646566), - FontWeight.w400), + style: fontTextStyle(12, Color(0xFF646566), FontWeight.w400), ), ), ], @@ -518,7 +511,7 @@ class _SourceLocationState extends State { 14, const Color(0xFF646566), FontWeight.w600), ), ), - const SizedBox(height: 12), + const SizedBox(height: 16), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF8270DB), @@ -532,7 +525,7 @@ class _SourceLocationState extends State { }, child: Text("Continue", style: fontTextStyle( - 14, Colors.white, FontWeight.w400)), + 14, Color(0xFFFFFFFF), FontWeight.w600)), ), ], ),