From ebb16d6f36b1d0c12db4de9eb9738434a3cae3dd Mon Sep 17 00:00:00 2001 From: venbaittech Date: Thu, 26 Dec 2024 10:58:31 +0530 Subject: [PATCH] manage user and mail issue fix --- assets/icons/drawer/logout.png | Bin 0 -> 10318 bytes lib/config/my_router.dart | 5 + .../auth_verification/registration.dart | 130 ++++----- lib/presentation/Screens/demo_home.dart | 273 ++++++++++++++++-- lib/presentation/Screens/profilepage.dart | 67 +++-- .../routes/auth_routes/login_route.dart | 12 +- .../tab_routes/home_route.dart | 155 +++++----- .../Drawer Items/edit_profile.dart | 65 +++-- .../Drawer Items/manage_users.dart | 4 +- .../drawer_routes/custom_drawer_routes.dart | 9 + pubspec.lock | 10 +- pubspec.yaml | 1 + 12 files changed, 526 insertions(+), 205 deletions(-) create mode 100644 assets/icons/drawer/logout.png diff --git a/assets/icons/drawer/logout.png b/assets/icons/drawer/logout.png new file mode 100644 index 0000000000000000000000000000000000000000..a0b94ff75722a7f8eb0445e627bba7dabcbe7254 GIT binary patch literal 10318 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 RegisterScreen(), ), + GoRoute( + path: '/DemoHome', + builder: (context, state) => ChartPage(), + ), GoRoute( path: '/mailverification', builder: (context, state) => EmailVerificationScreen( diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart index d83f2db4..0ec33c48 100644 --- a/lib/presentation/Screens/auth_verification/registration.dart +++ b/lib/presentation/Screens/auth_verification/registration.dart @@ -233,30 +233,6 @@ class _RegisterScreenState extends State { if (_formKey.currentState?.validate() ?? false) { if (isChecked) { try { - final existingUsers = await pb.collection('users').getList( - filter: 'email="${_emailController.text}"', - ); - - if (existingUsers.items.isNotEmpty) { - // Email already exists - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text('Email Exists'), - content: Text( - 'Email ID already exists. Please use a different email.'), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('OK'), - ), - ], - ); - }, - ); - return; // Stop registration process - } final adminAuth = await pb.admins .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); @@ -287,10 +263,33 @@ class _RegisterScreenState extends State { throw Exception('User registration failed: missing user ID'); } } catch (e) { - setState(() { - registrationFailed = true; - registrationSuccess = false; - }); + // Check if the error is due to an invalid or already used email + if (e + .toString() + .contains('The email is invalid or already in use.')) { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('Email Exists'), + content: Text( + 'Email ID already exists. Please use a different email.'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('OK'), + ), + ], + ); + }, + ); + } else { + // Handle other types of errors + setState(() { + registrationFailed = true; + registrationSuccess = false; + }); + } } } else { setState(() { @@ -452,7 +451,7 @@ class _RegisterScreenState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - SizedBox(height: screenheight / 6), + SizedBox(height: screenheight / 15), Text( 'Register', style: TextStyle( @@ -662,7 +661,7 @@ class _RegisterScreenState extends State { width: screenwidth / 1.3, child: ElevatedButton( onPressed: () { - // Add your login logic here + context.go('/'); }, style: ElevatedButton.styleFrom( backgroundColor: Color( @@ -671,44 +670,41 @@ class _RegisterScreenState extends State { borderRadius: BorderRadius.circular(10), ), ), - // child: Row( - // mainAxisSize: MainAxisSize.min, - // children: [ - // Text( - // "Login", - // style: TextStyle( - // fontSize: 16, color: Colors.white - // ), - // - // - // ), - // SizedBox(width: 8), - // Icon(Icons.arrow_forward, - // color: Colors.white), - // ], - // ), - - child: GestureDetector( - onTap: () { - // Navigate to LoginRoute - context.go('/'); - }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "Login", - style: TextStyle( - fontSize: 16, - color: Colors.white, - ), - ), - SizedBox(width: 8), - Icon(Icons.arrow_forward, - color: Colors.white), - ], - ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Login", + style: TextStyle( + fontSize: 16, color: Colors.white), + ), + SizedBox(width: 8), + Icon(Icons.arrow_forward, + color: Colors.white), + ], ), + + // child: GestureDetector( + // onTap: () { + // // Navigate to LoginRoute + // context.go('/'); + // }, + // child: Row( + // mainAxisSize: MainAxisSize.min, + // children: [ + // Text( + // "Login", + // style: TextStyle( + // fontSize: 16, + // color: Colors.white, + // ), + // ), + // SizedBox(width: 8), + // Icon(Icons.arrow_forward, + // color: Colors.white), + // ], + // ), + // ), ), ), SizedBox( diff --git a/lib/presentation/Screens/demo_home.dart b/lib/presentation/Screens/demo_home.dart index 402bc535..225f1b1b 100644 --- a/lib/presentation/Screens/demo_home.dart +++ b/lib/presentation/Screens/demo_home.dart @@ -1,29 +1,262 @@ +import 'dart:convert'; import 'package:flutter/material.dart'; -import 'dart:async'; +import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_charts/charts.dart'; // Import Syncfusion charts package +import 'package:http/http.dart' as http; -import 'package:uae_stat/domain/use_cases/language.dart'; - -import '../components/my_drawer.dart'; - -class DemoHome extends StatefulWidget { - @override - State createState() => _DemoHomeState(); +void main() { + runApp(MyApp()); } -class _DemoHomeState extends State { +class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return Scaffold( - drawer: const MyDrawer(), - appBar: AppBar( - backgroundColor: const Color(0xFFf8f9ff), - title: Text(context.translate('Home', 'نموذج الملاحظات')), - ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: Center( - child: Text('Home Page'), - )), + return MaterialApp( + home: ChartPage(), ); } } + +class ChartPage extends StatefulWidget { + @override + ChartPageState createState() => ChartPageState(); +} + +class ChartPageState extends State { + List chartsData = []; + bool isLoading = true; + + @override + void initState() { + super.initState(); + fetchChartData(); + } + + Future fetchChartData() async { + const baseUrl = + 'https://pb.venbait.in/api/custom/apicall'; // Replace with your server URL + final url = Uri.parse('$baseUrl?dataset=hotels'); + + try { + final response = await http.get(url); + if (response.statusCode == 200) { + setState(() { + chartsData = jsonDecode(response.body); + isLoading = false; + }); + } else { + throw Exception('Failed to load data'); + } + } catch (error) { + setState(() { + isLoading = false; + }); + print('Error fetching data: $error'); + } + } + + List parseLineChartData(List response) { + return response.map((entry) { + // Attempt to fetch the TIMEPERIOD + final rawTimePeriod = + entry['ObsKey']?['Year'] ?? entry['ObsKey']?['TIME_PERIOD']; + final formattedTimePeriod = rawTimePeriod != null + ? rawTimePeriod.toString() // Use as-is if valid + : 'Unknown'; // Fallback value if null + + // Parse the value or fallback to 0.0 + final value = + double.tryParse(entry['ObsValue']?['Value']?.toString() ?? '0.0') ?? + 0.0; + + return ChartData( + timePeriod: formattedTimePeriod, + value: value, + ); + }).toList(); + } + + List parseBarChartData(List response) { + return response + .asMap() + .entries + .map((entry) => ChartData( + timePeriod: entry.value['ObsKey']['TIME_PERIOD'] ?? + 'Unknown', // Fallback to 'Unknown' if null + value: double.tryParse( + entry.value['ObsValue']['Value'].toString()) ?? + 0.0, // Handle null/invalid value + )) + .toList(); + } + + Widget buildChart(dynamic chartData) { + print('chartData $chartData'); + switch (chartData['chart_type']) { + case 'line': + return SfCartesianChart( + primaryXAxis: CategoryAxis( + title: AxisTitle(text: 'Year'), + labelRotation: 45, // Rotate labels if they overlap + ), + title: ChartTitle(text: 'Hotel Estabhlishments'), + legend: Legend(isVisible: true), + tooltipBehavior: TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, + int pointIndex, int seriesIndex) { + return Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Text( + '${data.timePeriod}: ${formatNumber(data.value)}', + style: const TextStyle(color: Colors.black), + ), + ); + }, + ), + series: >[ + LineSeries( + dataSource: parseLineChartData(chartData['response']), + xValueMapper: (ChartData data, _) => data.timePeriod, + yValueMapper: (ChartData data, _) => data.value, + name: chartData['dataset'], + color: Colors.red, + dataLabelSettings: DataLabelSettings( + isVisible: true, + builder: (dynamic data, dynamic point, dynamic series, + int pointIndex, int seriesIndex) { + return Text( + formatNumber(data.value), + style: const TextStyle(fontSize: 12, color: Colors.black), + ); + }, + ), + ), + ], + ); + case 'bar': + return SfCartesianChart( + primaryXAxis: CategoryAxis(), + title: ChartTitle(text: 'Hotel Occupancy Rate'), + tooltipBehavior: TooltipBehavior( + enable: true, + builder: (dynamic data, dynamic point, dynamic series, + int pointIndex, int seriesIndex) { + return Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + ), + child: Text( + '${data.timePeriod}: ${formatNumber(data.value)}', + style: const TextStyle(color: Colors.black), + ), + ); + }, + ), + series: >[ + BarSeries( + dataSource: parseBarChartData(chartData['response']), + xValueMapper: (ChartData data, _) => data.timePeriod, + yValueMapper: (ChartData data, _) => data.value, + name: chartData['dataset'], + color: Colors.red, + dataLabelSettings: DataLabelSettings( + isVisible: true, + builder: (dynamic data, dynamic point, dynamic series, + int pointIndex, int seriesIndex) { + return Text( + formatNumber(data.value), + style: const TextStyle(fontSize: 12, color: Colors.black), + ); + }, + ), + // isTrackVisible: true, + // trackColor: Colors.red + ), + ], + ); + default: + return Center(child: Text('Unknown chart type')); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFF7DAFBC), + appBar: AppBar( + backgroundColor: Color(0xFF7DAFBC), + elevation: 0, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios_new, color: Colors.white), + onPressed: () { + context.go('/myhomepage'); + }, + ), + title: Text( + 'Charts', + style: TextStyle(color: Colors.white), + ), + ), + body: isLoading + ? Center(child: CircularProgressIndicator()) + : ListView.builder( + itemCount: chartsData.length, + itemBuilder: (context, index) { + return Card( + margin: EdgeInsets.all(10), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Text( + // 'Chart: ${chartsData[index]['chart_type']}', + // style: TextStyle( + // fontSize: 18, fontWeight: FontWeight.bold), + // ), + // SizedBox(height: 10), + Container( + height: 300, + child: buildChart(chartsData[index]), + ), + ], + ), + ), + ); + }, + ), + ); + } +} + +class ChartData { + final String timePeriod; + final double value; + final String formattedValue; + + ChartData({required this.timePeriod, required this.value}) + : formattedValue = formatNumber(value); +} + +String formatNumber(double value) { + if (value >= 1e12) { + return '${(value / 1e12).toStringAsFixed(2)} T'; // Trillions + } else if (value >= 1e9) { + return '${(value / 1e9).toStringAsFixed(2)} B'; // Billions + } else if (value >= 1e6) { + return '${(value / 1e6).toStringAsFixed(2)} M'; // Millions + } else if (value >= 1e5) { + return '${(value / 1e5).toStringAsFixed(2)} L'; // Lakhs + } else if (value >= 1e3) { + return '${(value / 1e3).toStringAsFixed(2)} K'; // Thousands + } + return value.toStringAsFixed(2); // Default to two decimal places +} diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart index 9c94e6ee..e003a18f 100644 --- a/lib/presentation/Screens/profilepage.dart +++ b/lib/presentation/Screens/profilepage.dart @@ -156,17 +156,39 @@ class _ProfileScreenState extends State { } } + // void _pickImage() async { + // final XFile? pickedFile = + // await _picker.pickImage(source: ImageSource.gallery); + // if (pickedFile != null) { + // setState(() { + // _profileImage = File(pickedFile.path); + // }); + // } + // } + + // Function to open the date picker + void _pickImage() async { final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery); if (pickedFile != null) { - setState(() { - _profileImage = File(pickedFile.path); - }); + final String fileExtension = + pickedFile.path.split('.').last.toLowerCase(); + if (fileExtension == 'jpg' || + fileExtension == 'jpeg' || + fileExtension == 'png' || + fileExtension == "heic") { + setState(() { + _profileImage = File(pickedFile.path); + }); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Please select a JPG, JPEG, or PNG file.')), + ); + } } } - // Function to open the date picker Future _pickDate() async { final DateTime today = DateTime.now(); final DateTime initialDate = _selectedDate ?? @@ -273,11 +295,12 @@ class _ProfileScreenState extends State { _resetFormFields(); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Profile updated successfully!"))); - if (role == 'admin') { - context.go('/manageuser'); - } else { - context.go('/myhomepage'); - } + // if (role == 'admin') { + // context.go('/manageuser'); + // } else { + // context.go('/myhomepage'); + // } + context.go('/myhomepage'); } catch (error) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Failed to update profile: $error"))); @@ -370,8 +393,10 @@ class _ProfileScreenState extends State { children: [ Text( "User Name", - style: - TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), ), ], ), @@ -380,7 +405,7 @@ class _ProfileScreenState extends State { controller: _usernameController, focusNode: _focusNodes[0], decoration: InputDecoration( - hintText: _showHints[0] ? 'Mohammad Hassan' : null, + hintText: _showHints[0] ? 'Enter the User Name' : null, hintStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -393,9 +418,11 @@ class _ProfileScreenState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "E-mail", - style: - TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + "Email ID", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), ), ], ), @@ -418,7 +445,7 @@ class _ProfileScreenState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "Full Name", + "Full Name*", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), ), @@ -444,7 +471,7 @@ class _ProfileScreenState extends State { controller: _fullNameController, focusNode: _focusNodes[2], decoration: InputDecoration( - hintText: _showHints[2] ? 'Enter the Full Name' : null, + hintText: _showHints[2] ? 'Enter the name' : null, hintStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -473,9 +500,9 @@ class _ProfileScreenState extends State { border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), - hintText: - _showHints[3] ? 'Select your Date of Birth' : null, - //hintText: 'Select your Date of Birth', + hintText: _showHints[3] ? 'DD/MM/YYYY' : null, + //_showHints[3] ? 'Select your Date of Birth' : null, + hintStyle: TextStyle(color: Colors.grey), suffixIcon: const Icon(Icons.arrow_drop_down_sharp), ), readOnly: true, diff --git a/lib/presentation/routes/auth_routes/login_route.dart b/lib/presentation/routes/auth_routes/login_route.dart index 7e56df9f..41dc0b37 100644 --- a/lib/presentation/routes/auth_routes/login_route.dart +++ b/lib/presentation/routes/auth_routes/login_route.dart @@ -256,12 +256,12 @@ class LoginRoute extends HookConsumerWidget { print(isProfileComplete); if (isProfileComplete) { print('home'); - if (role == 'admin') { - context.go('/manageuser'); - } else { - context.go('/myhomepage'); - } - // context.go('/myhomepage'); + // if (role == 'admin') { + // context.go('/myhomepage'); + // } else { + // context.go('/myhomepage'); + // } + context.go('/myhomepage'); } else { print('profile'); if (userId != null && userId.isNotEmpty) { diff --git a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart index 1c2fe332..cc4702c4 100644 --- a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart +++ b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart @@ -161,6 +161,7 @@ // } // } import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import '../../drawer_routes/custom_drawer_routes.dart'; class MyHomePage extends StatefulWidget { @@ -176,16 +177,16 @@ class _MyHomePageState extends State { double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; return BaseScaffold( - title: Center(child: SizedBox(height : myheight/5, width : mywidth/3,child: Image(image: AssetImage('assets/logos/uae_stat.png')))), + title: Center( + child: SizedBox( + height: myheight / 5, + width: mywidth / 3, + child: Image(image: AssetImage('assets/logos/uae_stat.png')))), body: EconomyStats(), ); } } - - - - class EconomyStats extends StatelessWidget { const EconomyStats({Key? key}) : super(key: key); @@ -193,24 +194,26 @@ class EconomyStats extends StatelessWidget { Widget build(BuildContext context) { return SingleChildScrollView( child: Padding( - padding: EdgeInsets.only(left: 10,right: 10), + padding: EdgeInsets.only(left: 10, right: 10), child: Column( children: [ // Header Section - RoundedCornerContainer( - text: 'ECONOMY', - backgroundColor: Color(0xFF7DAFBC), - textStyle: const TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), + RoundedCornerContainer( + text: 'ECONOMY', + backgroundColor: Color(0xFF7DAFBC), + textStyle: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), // Grid Section // ECONOMY DETAILS Padding( - padding: const EdgeInsets.only(top: 10,), + padding: const EdgeInsets.only( + top: 10, + ), child: Column( children: [ // First Row @@ -224,11 +227,12 @@ class EconomyStats extends StatelessWidget { bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), ), - InfoCard( + InfoCard( title: 'Inflation Rate', subtitle: '(2022)', value: '4.82%', - bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + bordercolor: Color(0xFF7DAFBC), + textcolor: Color(0xFF7DAFBC), ), ], ), @@ -236,18 +240,20 @@ class EconomyStats extends StatelessWidget { // Second Row Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ + children: [ InfoCard( title: 'Trade Value', subtitle: '(Jan - Jan 2024) - AED', value: '215.4B', - bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + bordercolor: Color(0xFF7DAFBC), + textcolor: Color(0xFF7DAFBC), ), InfoCard( title: 'Hotel Guests', subtitle: '(2022)', value: '25.21M', - bordercolor: Color(0xFF7DAFBC), textcolor: Color(0xFF7DAFBC), + bordercolor: Color(0xFF7DAFBC), + textcolor: Color(0xFF7DAFBC), ), ], ), @@ -264,7 +270,9 @@ class EconomyStats extends StatelessWidget { // SOCIAL DETAILS Padding( - padding: const EdgeInsets.only(top: 10,), + padding: const EdgeInsets.only( + top: 10, + ), child: Column( children: [ // First Row @@ -291,7 +299,7 @@ class EconomyStats extends StatelessWidget { // Second Row Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ + children: [ InfoCard( title: 'Hospitals (Gov )', subtitle: '(Jan - Jan 2024) - AED', @@ -321,12 +329,15 @@ class EconomyStats extends StatelessWidget { // ENVIRONMENT DETAILS Padding( - padding: const EdgeInsets.only(top: 10,), + padding: const EdgeInsets.only( + top: 10, + ), child: Column( children: [ // First Row Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, children: [ InfoCard( title: 'Electricity', @@ -347,8 +358,9 @@ class EconomyStats extends StatelessWidget { const SizedBox(height: 10), // Second Row Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ InfoCard( title: 'Export of oil', subtitle: '(Jan - Jan 2024) - AED', @@ -386,13 +398,11 @@ class RoundedCornerContainer extends StatelessWidget { final Color backgroundColor; final TextStyle? textStyle; - const RoundedCornerContainer({ Key? key, required this.text, this.backgroundColor = Colors.blue, this.textStyle, - }) : super(key: key); @override @@ -417,7 +427,6 @@ class RoundedCornerContainer extends StatelessWidget { } } - class InfoCard extends StatelessWidget { final String title; final String subtitle; @@ -425,60 +434,66 @@ class InfoCard extends StatelessWidget { final Color bordercolor; final Color? textcolor; - const InfoCard({ + const InfoCard({ Key? key, required this.title, required this.subtitle, - required this.value, required this.bordercolor,this.textcolor, + required this.value, + required this.bordercolor, + this.textcolor, }) : super(key: key); @override Widget build(BuildContext context) { double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; + return Expanded( - child: - Container( - height: myheight/9, - width: mywidth/4, - margin: const EdgeInsets.symmetric(horizontal: 8), - decoration: BoxDecoration( - border: Border.all(color: bordercolor), - borderRadius: BorderRadius.circular(8), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: Text( - title, - //textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, + child: GestureDetector( + onTap: () { + context.go('/DemoHome'); + }, + child: Container( + height: myheight / 9, + width: mywidth / 4, + margin: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + border: Border.all(color: bordercolor), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: Text( + title, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: Colors.black, + ), ), ), - ), - const SizedBox(height: 2), - Text( - subtitle, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 12, - color: Colors.grey, + const SizedBox(height: 2), + Text( + subtitle, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), ), - ), - const SizedBox(height: 2), - Text( - value, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: textcolor ?? Colors.black + const SizedBox(height: 2), + Text( + value, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: textcolor ?? Colors.black, + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart index 00d0c486..8c513234 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart @@ -194,17 +194,39 @@ class _EditProfileState extends State { } } + // void _pickImage() async { + // final XFile? pickedFile = + // await _picker.pickImage(source: ImageSource.gallery); + // if (pickedFile != null) { + // setState(() { + // _profileImage = File(pickedFile.path); + // }); + // } + // } + + // Function to open the date picker + void _pickImage() async { final XFile? pickedFile = await _picker.pickImage(source: ImageSource.gallery); if (pickedFile != null) { - setState(() { - _profileImage = File(pickedFile.path); - }); + final String fileExtension = + pickedFile.path.split('.').last.toLowerCase(); + if (fileExtension == 'jpg' || + fileExtension == 'jpeg' || + fileExtension == 'png' || + fileExtension == "heic") { + setState(() { + _profileImage = File(pickedFile.path); + }); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Please select a JPG, JPEG, or PNG file.')), + ); + } } } - // Function to open the date picker Future _pickDate() async { final DateTime today = DateTime.now(); final DateTime initialDate = _selectedDate ?? @@ -398,7 +420,9 @@ class _EditProfileState extends State { Text( "User Name", style: TextStyle( - fontSize: 16, fontWeight: FontWeight.w500), + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), ), ], ), @@ -407,7 +431,7 @@ class _EditProfileState extends State { controller: _usernameController, focusNode: _focusNodes[0], decoration: InputDecoration( - hintText: _showHints[0] ? 'Mohammad Hassan' : null, + // hintText: _showHints[0] ? 'Mohammad Hassan' : null, hintStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -420,9 +444,11 @@ class _EditProfileState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "E-mail", + "Email ID", style: TextStyle( - fontSize: 16, fontWeight: FontWeight.w500), + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), ), ], ), @@ -431,10 +457,7 @@ class _EditProfileState extends State { controller: _emailController, focusNode: _focusNodes[1], decoration: InputDecoration( - hintText: _showHints[1] - ? 'mohammad.hassan@fcsc.gov.ae' - : null, - hintStyle: TextStyle(color: Colors.grey), + // hintText: _showHints[1]? 'mohammad.hassan@fcsc.gov.ae': null, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), @@ -446,9 +469,11 @@ class _EditProfileState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text( - "Full Name", + "Full Name*", style: TextStyle( - fontSize: 16, fontWeight: FontWeight.w500), + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), ), ], ), @@ -471,7 +496,7 @@ class _EditProfileState extends State { controller: _fullNameController, focusNode: _focusNodes[2], decoration: InputDecoration( - hintText: _showHints[2] ? 'Mohammad' : null, + // hintText: _showHints[2] ? 'Mohammad' : null, hintStyle: TextStyle(color: Colors.grey), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -490,7 +515,9 @@ class _EditProfileState extends State { Text( "Date of Birth*", style: TextStyle( - fontSize: 16, fontWeight: FontWeight.w500), + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), ), ], ), @@ -502,10 +529,8 @@ class _EditProfileState extends State { border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), - hintText: _showHints[3] - ? 'Select your Date of Birth' - : null, - //hintText: 'Select your Date of Birth', + // hintText: _showHints[3] ? 'Select your Date of Birth' : null, + hintStyle: TextStyle(color: Colors.grey), suffixIcon: const Icon(Icons.arrow_drop_down_sharp), enabled: !_isProfileCompleted, ), diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart index deab917f..8652db61 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/manage_users.dart @@ -43,7 +43,9 @@ class _ManageUserRouterState extends State { try { await _pb.admins .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); - final result = await _pb.collection('users').getFullList(); + final result = await _pb.collection('users').getFullList( + filter: 'role="user"', + ); setState(() { userData = result.map((record) { diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index 981a32fe..8aa0afea 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -199,6 +199,15 @@ class _BaseScaffoldState extends State { title: Text('Manage User'), onTap: () => context.go('/manageuser'), ), + ListTile( + leading: SizedBox( + height: myheight / 15, + width: mywidth / 15, + child: Image( + image: AssetImage('assets/icons/drawer/logout.png'))), + title: Text('Logout'), + onTap: () => context.go('/'), + ), ], ), ), diff --git a/pubspec.lock b/pubspec.lock index 67247bd5..7d1ab196 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -841,6 +841,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.12.16+1" + material_charts: + dependency: "direct main" + description: + name: material_charts + sha256: "3950a910eeb8f5dca7040a68d526a086a9512f87da5c2b172495a5fcab0f6dc3" + url: "https://pub.dev" + source: hosted + version: "0.0.23" material_color_utilities: dependency: transitive description: @@ -1501,5 +1509,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.5.0 <4.0.0" + dart: ">=3.5.2 <4.0.0" flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3fac9859..ebd8679b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: mailer: ^6.2.0 image_picker: ^1.1.2 syncfusion_flutter_charts: ^28.1.33 + material_charts: ^0.0.23 dependency_overrides: fading_edge_scrollview: ^4.1.1