From f9a96d881af9b52be3addc4fbf3ccd4277ef4f0d Mon Sep 17 00:00:00 2001 From: Vaibhav Date: Tue, 20 Aug 2024 17:43:22 +0530 Subject: [PATCH] Update UI of Daily Task screen & kyc --- lib/provider/collect_kyc_provider.dart | 10 +- lib/screens/Visit_Dealers_screen.dart | 4 +- lib/screens/daily_tasks_screen.dart | 315 +++++++++++----- lib/screens/retailer_details_screen.dart | 436 +++++++++++------------ lib/screens/update_inventory_screen.dart | 1 - 5 files changed, 443 insertions(+), 323 deletions(-) diff --git a/lib/provider/collect_kyc_provider.dart b/lib/provider/collect_kyc_provider.dart index a6cbfea..f3d0e39 100644 --- a/lib/provider/collect_kyc_provider.dart +++ b/lib/provider/collect_kyc_provider.dart @@ -14,13 +14,14 @@ class CollectKycProvider extends ChangeNotifier { CollectKycProvider() { getPd(); } - + String? selectedTask; TextEditingController country = TextEditingController(text: "India"); TextEditingController state = TextEditingController(); TextEditingController city = TextEditingController(); late TabController tabController; final _apiClient = ApiClient(); + final selectTaskController= TextEditingController(); final tradeNameController = TextEditingController(); final nameController = TextEditingController(); final addressController = TextEditingController(); @@ -119,6 +120,8 @@ class CollectKycProvider extends ChangeNotifier { bool get isLoading => _isLoading; List pdList = []; + get taskList => ('Task 1','Task 2'); + void setLoading(bool loading) { _isLoading = loading; notifyListeners(); @@ -278,4 +281,9 @@ class CollectKycProvider extends ChangeNotifier { } } } + + void setTask(String s) { + selectedTask = s; + notifyListeners(); + } } diff --git a/lib/screens/Visit_Dealers_screen.dart b/lib/screens/Visit_Dealers_screen.dart index 0face39..105f068 100644 --- a/lib/screens/Visit_Dealers_screen.dart +++ b/lib/screens/Visit_Dealers_screen.dart @@ -27,8 +27,8 @@ class VisitDealersScreenState extends State { final followUpActionsController = TextEditingController(); final nextVisitDateController = TextEditingController(); - String selectedPurpose = 'Sales/Liquidation'; - List purposeOptions = ['Sales/Liquidation', 'Dues collection', 'Others']; + String selectedPurpose = 'Sales'; + List purposeOptions = ['Sales', 'Dues collection', 'Others']; Future _pickImage() async { final ImagePicker picker = ImagePicker(); diff --git a/lib/screens/daily_tasks_screen.dart b/lib/screens/daily_tasks_screen.dart index 849cdd1..e2cd2ed 100644 --- a/lib/screens/daily_tasks_screen.dart +++ b/lib/screens/daily_tasks_screen.dart @@ -1,114 +1,251 @@ -import 'package:cheminova/screens/collect_kyc_screen.dart'; -import 'package:cheminova/screens/update_inventory_screen.dart'; -import 'package:cheminova/screens/display_sales_screen.dart'; import 'package:flutter/material.dart'; -import 'package:cheminova/screens/Visit_Dealers_screen.dart'; +import 'package:cheminova/screens/visit_dealers_screen.dart'; +import 'package:cheminova/screens/display_sales_screen.dart'; +import 'package:cheminova/screens/update_inventory_screen.dart'; +import 'package:cheminova/screens/collect_kyc_screen.dart'; import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_drawer.dart'; import 'package:cheminova/widgets/common_background.dart'; +import 'package:intl/intl.dart'; -class DailyTasksScreen extends StatelessWidget { +class DailyTasksScreen extends StatefulWidget { const DailyTasksScreen({super.key}); + @override + State createState() => _DailyTasksScreenState(); +} + +class _DailyTasksScreenState extends State { + final List _tabTitles = ['NEW', 'PENDING', 'COMPLETED']; + int _selectedTabIndex = 0; + @override Widget build(BuildContext context) { return Scaffold( extendBodyBehindAppBar: true, - appBar: CommonAppBar( - backgroundColor: Colors.transparent, - elevation: 0, - actions: [ - IconButton( - onPressed: () { - Navigator.pop(context); - }, - icon: Image.asset('assets/Back_attendance.png'), - padding: const EdgeInsets.only(right: 20), - ), - ], - title: const Center( - child: Text( - 'Daily Tasks', - style: TextStyle(color: Colors.black87, fontSize: 20), - ), - ), - ), + appBar: _buildAppBar(), drawer: const CommonDrawer(), body: CommonBackground( child: SafeArea( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: ListView( - children: [ - _buildCustomCard( - 'Visit Dealers/Retailers', - '', - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const VisitDealersScreen(), - ), - ); - }, - ), - const SizedBox(height: 5), - _buildCustomCard( - 'Update Sales Data', - '', - onTap: () { - Navigator.push(context,MaterialPageRoute(builder: (context) => const DisplaySalesScreen(),)); - }, - ), - const SizedBox(height: 5), - _buildCustomCard('Update Inventory Data', '',onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => const UpdateInventoryScreen(),)); - },), - const SizedBox(height: 5), - _buildCustomCard('Collect KYC Documents', '',onTap:() { - Navigator.push(context, MaterialPageRoute( - builder: (context) => const CollectKycScreen(),)); - }, ), - ], - ), - ), - ], - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildCustomTabBar(), + Expanded( + child: _buildTaskList(_selectedTabIndex), + ), + ], ), ), ), ); } - Widget _buildCustomCard(String title, String subtitle, {void Function()? onTap}) { - return Container( - margin: const EdgeInsets.only(bottom: 10), - decoration: BoxDecoration( - color: Colors.indigo, - border: Border.all(color: Colors.white), - borderRadius: BorderRadius.circular(10), - ), - child: ListTile( - title: Text( - title, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w800, - fontSize: 18, - fontFamily: 'Anek'), + PreferredSizeWidget _buildAppBar() { + return CommonAppBar( + backgroundColor: Colors.transparent, + elevation: 0, + actions: [ + IconButton( + onPressed: () => Navigator.pop(context), + icon: Image.asset('assets/Back_attendance.png'), + padding: const EdgeInsets.only(right: 20), ), - subtitle: subtitle.isNotEmpty - ? Text( - subtitle, - style: const TextStyle(color: Colors.white70, fontSize: 13), - ) - : null, - onTap: onTap, + ], + title: const Text( + 'Daily Tasks', + style: TextStyle(color: Colors.black87, fontSize: 20), ), ); } + + Widget _buildCustomTabBar() { + return Container( + height: 60, + margin: const EdgeInsets.symmetric(vertical: 16, horizontal: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: List.generate(_tabTitles.length, (index) { + return GestureDetector( + onTap: () => setState(() => _selectedTabIndex = index), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + decoration: BoxDecoration( + gradient: _selectedTabIndex == index + ? const LinearGradient( + colors: [Color(0xff004791), Color(0xff1a73e8)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ) + : null, + color: _selectedTabIndex == index + ? Colors.transparent + : Colors.white, + borderRadius: BorderRadius.circular(10), + border: Border.all(color: Colors.black), + boxShadow: [ + if (_selectedTabIndex == index) + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 6, + offset: const Offset(0, 4), + ), + ], + ), + child: Row( + children: [ + Icon( + _getTabIcon(index), + color: _selectedTabIndex == index + ? Colors.white + : Colors.black, + ), + const SizedBox(width: 8), + Text( + _tabTitles[index], + style: TextStyle( + color: _selectedTabIndex == index + ? Colors.white + : Colors.black, + fontWeight: _selectedTabIndex == index + ? FontWeight.bold + : FontWeight.normal, + ), + ), + ], + ), + ), + ); + }), + ), + ); + } + + IconData _getTabIcon(int index) { + switch (index) { + case 0: + return Icons.new_releases; + case 1: + return Icons.pending; + case 2: + return Icons.check_circle; + default: + return Icons.new_releases; + } + } + + Widget _buildTaskList(int tabIndex) { + List tasks; + switch (tabIndex) { + case 0: + tasks = _newTasks; + break; + case 1: + tasks = _pendingTasks; + break; + case 2: + tasks = _completedTasks; + break; + default: + tasks = []; + } + + return ListView.separated( + padding: const EdgeInsets.all(16), + itemCount: tasks.length, + separatorBuilder: (context, index) => const SizedBox(height: 8), + itemBuilder: (context, index) => _buildTaskCard(tasks[index]), + ); + } + + Widget _buildTaskCard(TaskItem task) { + if (task is KycTaskItem) { + return Card( + color: Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + child: Column( + children: [ + ListTile( + leading: const Icon(Icons.task, color: Colors.blueAccent), + title: Text( + task.title, + style: const TextStyle( + color: Colors.black87, + fontWeight: FontWeight.w700, + fontSize: 16, + fontFamily: 'Anek', + ), + ), + trailing: + const Icon(Icons.arrow_forward_ios, color: Colors.black87), + onTap: () => Navigator.push(context, + MaterialPageRoute(builder: (context) => task.screen)), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Note: ${task.note}'), + Text('Date: ${task.date.toString().split(' ')[0]}'), + Text('Priority: ${task.Low}'), + ], + ), + ), + ], + ), + ); + } else { + return Card( + color: Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), + child: ListTile( + leading: const Icon(Icons.task, color: Colors.blueAccent), + title: Text( + task.title, + style: const TextStyle( + color: Colors.black87, + fontWeight: FontWeight.w700, + fontSize: 16, + fontFamily: 'Anek', + ), + ), + trailing: const Icon(Icons.arrow_forward_ios, color: Colors.black87), + onTap: () => Navigator.push( + context, MaterialPageRoute(builder: (context) => task.screen)), + ), + ); + } + } + + final List _newTasks = [ + KycTaskItem('Collect KYC Documents', const CollectKycScreen(), + 'Collect KYC documents from ABC Trader', DateFormat('dd/MM/yyyy').format(DateTime.now()).toString(), 'Priority'), + TaskItem('Update Inventory Data', const UpdateInventoryScreen()), + ]; + + final List _pendingTasks = [ + TaskItem('Update Sales Data', const DisplaySalesScreen()), + TaskItem('Visit Dealers/Retailers', const VisitDealersScreen()), + ]; + + final List _completedTasks = [ + TaskItem('Completed Task 1', const Placeholder()), + TaskItem('Completed Task 2', const Placeholder()), + ]; +} + +class TaskItem { + final String title; + final Widget screen; + + TaskItem(this.title, this.screen); +} + +class KycTaskItem extends TaskItem { + final String note; + final String date; + final String Low; + + KycTaskItem(super.title, super.screen, this.note, this.date, this.Low); } diff --git a/lib/screens/retailer_details_screen.dart b/lib/screens/retailer_details_screen.dart index b1078d9..89284a3 100644 --- a/lib/screens/retailer_details_screen.dart +++ b/lib/screens/retailer_details_screen.dart @@ -21,7 +21,7 @@ class RetailerDetailsScreenState extends State { Widget build(BuildContext context) { return Consumer( builder: (BuildContext context, CollectKycProvider value, - Widget? child) => + Widget? child) => Padding( padding: const EdgeInsets.all(16.0), child: SingleChildScrollView( @@ -43,186 +43,212 @@ class RetailerDetailsScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - CommonTextFormField( - title: 'Trade Name', - fillColor: Colors.white, - validator: (String? value) { - if (value!.isEmpty) { - return 'Trade Name cannot be empty'; - } - return null; - }, - controller: value.tradeNameController), - const SizedBox(height: 15), - CommonTextFormField( - title: 'Name', - fillColor: Colors.white, - validator: (String? value) { - if (value!.isEmpty) { - return 'Name cannot be empty'; - } - return null; - }, - controller: value.nameController), - const SizedBox(height: 15), - CommonTextFormField( - title: 'Address', - fillColor: Colors.white, - validator: (String? value) { - if (value!.isEmpty) { - return 'Address cannot be empty'; - } - return null; - }, - controller: value.addressController), - const SizedBox(height: 15), - CSCPicker( - defaultCountry: CscCountry.India, - - disableCountry: true, - onCountryChanged: (val) { - setState(() { - value.country.text = val; - }); - }, - onStateChanged: (val) { - setState(() { - value.state.text = val ?? ''; - }); - }, - onCityChanged: (val) { - setState(() { - value.city.text = val ?? ''; - }); - }, - ), - const SizedBox(height: 15), - CommonTextFormField( - title: 'District', - fillColor: Colors.white, - validator: (String? value) { - if (value!.isEmpty) { - return 'District cannot be empty'; - } - return null; - }, - controller: value.districtController), - const SizedBox(height: 15), - CommonTextFormField( - maxLength: 6, - title: 'Pincode', - fillColor: Colors.white, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly + DropdownButtonFormField( + decoration: InputDecoration( + fillColor: Colors.white, + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none)), + hint: Text("Select a task"), + value: value.selectedTask, + onChanged: (String? newValue) { + value.setTask(newValue!); + }, + items:["task1", "task2", "task3"].map((String task) { + return DropdownMenuItem( + value: task, + child: Text(task), + ); + }).toList(), + ), + IgnorePointer( + ignoring: value.selectedTask == null, + child: Column( + children: [ + const SizedBox(height: 15), + CommonTextFormField( + title: 'Trade Name', + fillColor: Colors.white, + validator: (String? value) { + if (value!.isEmpty) { + return 'Trade Name cannot be empty'; + } + return null; + }, + controller: value.tradeNameController), + const SizedBox(height: 15), + CommonTextFormField( + title: 'Name', + fillColor: Colors.white, + validator: (String? value) { + if (value!.isEmpty) { + return 'Name cannot be empty'; + } + return null; + }, + controller: value.nameController), + const SizedBox(height: 15), + CommonTextFormField( + title: 'Address', + fillColor: Colors.white, + validator: (String? value) { + if (value!.isEmpty) { + return 'Address cannot be empty'; + } + return null; + }, + controller: value.addressController), + const SizedBox(height: 15), + CSCPicker( + defaultCountry: CscCountry.India, + disableCountry: true, + onCountryChanged: (val) { + setState(() { + value.country.text = val; + }); + }, + onStateChanged: (val) { + setState(() { + value.state.text = val ?? ''; + }); + }, + onCityChanged: (val) { + setState(() { + value.city.text = val ?? ''; + }); + }, + ), + const SizedBox(height: 15), + CommonTextFormField( + title: 'District', + fillColor: Colors.white, + validator: (String? value) { + if (value!.isEmpty) { + return 'District cannot be empty'; + } + return null; + }, + controller: value.districtController), + const SizedBox(height: 15), + CommonTextFormField( + maxLength: 6, + title: 'Pincode', + fillColor: Colors.white, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + validator: (String? value) { + if (value!.isEmpty) { + return 'Pincode cannot be empty'; + } + return null; + }, + controller: value.pinCodeController), + const SizedBox(height: 15), + CommonTextFormField( + maxLength: 10, + title: 'Mobile Number', + fillColor: Colors.white, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + validator: (String? value) { + if (value!.isEmpty) { + return 'Mobile Number cannot be empty'; + } + return null; + }, + controller: value.mobileNumberController), + const SizedBox(height: 15), + CommonTextFormField( + maxLength: 12, + title: 'Aadhar Number', + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly + ], + fillColor: Colors.white, + validator: (String? value) { + if (value!.isEmpty) { + return 'Aadhar Number cannot be empty'; + } + return null; + }, + controller: value.aadharNumberController), + const SizedBox(height: 15), + CommonTextFormField( + inputFormatters: [ + UpperCaseTextFormatter(), + ], + maxLength: 10, + title: 'PAN Number', + fillColor: Colors.white, + validator: (String? value) { + if (value!.isEmpty) { + return 'PAN Number cannot be empty'; + } + return null; + }, + controller: value.panNumberController), + const SizedBox(height: 15), + CommonTextFormField( + inputFormatters: [ + UpperCaseTextFormatter(), + ], + maxLength: 15, + title: 'GST Number', + fillColor: Colors.white, + validator: (String? value) { + if (value!.isEmpty) { + return 'GST Number cannot be empty'; + } + return null; + }, + controller: value.gstNumberController), + const SizedBox(height: 15), + DropdownButtonFormField( + decoration: InputDecoration( + fillColor: Colors.white, + filled: true, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide.none), + hintText: 'Mapped Principal Distributor'), + value: value.selectedDistributor, + items: value.pdList.map((GetPdResponse pd) { + return DropdownMenuItem( + value: pd.sId, child: Text(pd.name ?? '')); + }).toList(), + onChanged: (String? newValue) { + setState(() { + value.selectedDistributor = newValue; + }); + }, + validator: (String? value) { + if (value == null || value.isEmpty) { + return 'Mapped Principal Distributor cannot be empty'; + } + return null; + }, + ), + const SizedBox(height: 30), + Align( + alignment: Alignment.center, + child: CommonElevatedButton( + borderRadius: 30, + width: double.infinity, + height: kToolbarHeight - 10, + text: 'CONTINUE', + backgroundColor: const Color(0xff004791), + onPressed: () { + if (value.retailerDetailsFormKey.currentState! + .validate()) { + value.tabController.animateTo(1); + } + }, + ), + ), ], - validator: (String? value) { - if (value!.isEmpty) { - return 'Pincode cannot be empty'; - } - return null; - }, - controller: value.pinCodeController), - const SizedBox(height: 15), - CommonTextFormField( - maxLength: 10, - title: 'Mobile Number', - fillColor: Colors.white, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - validator: (String? value) { - if (value!.isEmpty) { - return 'Mobile Number cannot be empty'; - } - return null; - }, - controller: value.mobileNumberController), - const SizedBox(height: 15), - CommonTextFormField( - maxLength: 12, - title: 'Aadhar Number', - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - fillColor: Colors.white, - validator: (String? value) { - if (value!.isEmpty) { - return 'Aadhar Number cannot be empty'; - } - return null; - }, - controller: value.aadharNumberController), - const SizedBox(height: 15), - CommonTextFormField( - inputFormatters: [ - UpperCaseTextFormatter(), - ], - maxLength: 10, - title: 'PAN Number', - fillColor: Colors.white, - validator: (String? value) { - if (value!.isEmpty) { - return 'PAN Number cannot be empty'; - } - return null; - }, - controller: value.panNumberController), - const SizedBox(height: 15), - CommonTextFormField( - inputFormatters: [ - UpperCaseTextFormatter(), - ], - maxLength: 15, - title: 'GST Number', - fillColor: Colors.white, - validator: (String? value) { - if (value!.isEmpty) { - return 'GST Number cannot be empty'; - } - return null; - }, - controller: value.gstNumberController), - const SizedBox(height: 15), - DropdownButtonFormField( - decoration: InputDecoration( - fillColor: Colors.white, - filled: true, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none), - hintText: 'Mapped Principal Distributor'), - value: value.selectedDistributor, - items: value.pdList.map((GetPdResponse pd) { - return DropdownMenuItem( - value: pd.sId, child: Text(pd.name ?? '')); - }).toList(), - onChanged: (String? newValue) { - setState(() { - value.selectedDistributor = newValue; - }); - }, - validator: (String? value) { - if (value == null || value.isEmpty) { - return 'Mapped Principal Distributor cannot be empty'; - } - return null; - }, - ), - const SizedBox(height: 30), - Align( - alignment: Alignment.center, - child: CommonElevatedButton( - borderRadius: 30, - width: double.infinity, - height: kToolbarHeight - 10, - text: 'CONTINUE', - backgroundColor: const Color(0xff004791), - onPressed: () { - if (value.retailerDetailsFormKey.currentState! - .validate()) { - value.tabController.animateTo(1); - } - }, ), ), ], @@ -235,53 +261,3 @@ class RetailerDetailsScreenState extends State { )); } } - -class CustomCountryStateCityPicker extends StatelessWidget { - final TextEditingController country; - final TextEditingController state; - final TextEditingController city; - final Color dialogColor; - final InputDecoration textFieldDecoration; - - const CustomCountryStateCityPicker({ - Key? key, - required this.country, - required this.state, - required this.city, - required this.dialogColor, - required this.textFieldDecoration, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - TextFormField( - controller: country, - decoration: textFieldDecoration.copyWith( - labelText: 'Country', - enabled: false, - ), - ), - const SizedBox(height: 15), - TextFormField( - controller: state, - decoration: textFieldDecoration.copyWith(labelText: 'State'), - readOnly: true, - onTap: () { - // Implement state selection logic for India - }, - ), - const SizedBox(height: 15), - TextFormField( - controller: city, - decoration: textFieldDecoration.copyWith(labelText: 'City'), - readOnly: true, - onTap: () { - // Implement city selection logic based on selected state - }, - ), - ], - ); - } -} diff --git a/lib/screens/update_inventory_screen.dart b/lib/screens/update_inventory_screen.dart index 0aacede..a56e741 100644 --- a/lib/screens/update_inventory_screen.dart +++ b/lib/screens/update_inventory_screen.dart @@ -82,7 +82,6 @@ class _UpdateInventoryScreenState extends State { }).toList(), onChanged: (val) => value.updatePdRdValue(val), - // Disable the dropdown if no distributor type is selected isExpanded: true, isDense: true, iconSize: 24,