Login API

This commit is contained in:
kratikpal 2024-07-31 12:12:58 +05:30
parent bf492cbac2
commit 288d3caa9f
13 changed files with 658 additions and 333 deletions

View File

@ -1,17 +1,13 @@
import 'package:cheminova/provider/collect_kyc_provider.dart'; import 'package:cheminova/provider/collect_kyc_provider.dart';
import 'package:cheminova/screens/Attendance_success.dart'; import 'package:cheminova/provider/user_provider.dart';
import 'package:cheminova/screens/forgot_password_screen.dart';
import 'package:cheminova/screens/login_screen.dart';
import 'package:cheminova/screens/mark_attendence_screen.dart';
import 'package:cheminova/screens/on_leave_screen.dart';
import 'package:cheminova/screens/splash_screen.dart'; import 'package:cheminova/screens/splash_screen.dart';
import 'package:cheminova/services/snackbar_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
void main() { void main() {
runApp(MultiProvider(providers: [ runApp(MultiProvider(providers: [
ChangeNotifierProvider(create: (context) => CollectKycProvider()) ChangeNotifierProvider(create: (context) => CollectKycProvider()),
ChangeNotifierProvider(create: (_) => UserProvider()),
], child: const MyApp())); ], child: const MyApp()));
} }

View File

@ -0,0 +1,26 @@
class UserModel {
String id;
String name;
String email;
String uniqueId;
bool isVerified;
UserModel({
required this.id,
required this.name,
required this.email,
required this.uniqueId,
required this.isVerified,
});
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
id: json['_id'],
name: json['name'],
email: json['email'],
uniqueId: json['uniqueId'],
isVerified: json['isVerified'],
);
}
}

View File

@ -23,8 +23,10 @@ class LoginProvider extends ChangeNotifier {
Future<(bool, String)> login() async { Future<(bool, String)> login() async {
setLoading(true); setLoading(true);
try { try {
Response response = await _apiClient.post(ApiUrls.loginUrl, Response response = await _apiClient.post(ApiUrls.loginUrl, data: {
data: {'email': emailController.text.trim(), 'password': passwordController.text.trim()}); 'email': emailController.text.trim(),
'password': passwordController.text.trim()
});
setLoading(false); setLoading(false);
if (response.statusCode == 200) { if (response.statusCode == 200) {
await _storageService.write( await _storageService.write(
@ -33,9 +35,22 @@ class LoginProvider extends ChangeNotifier {
} else { } else {
return (false, response.data['message'].toString()); return (false, response.data['message'].toString());
} }
} on DioException catch (e) {
setLoading(false);
if (e.response?.data is Map<String, dynamic>) {
return (
false,
e.response?.data['message'].toString() ?? 'something went wrong'
);
} else if (e.response?.data is String) {
return (false, e.response?.data.toString() ?? 'something went wrong');
} else {
return (false, 'something went wrong');
}
} catch (e) { } catch (e) {
setLoading(false); setLoading(false);
return (false, 'Something want wrong'); return (false, 'something went wrong');
} }
} }
} }

View File

@ -0,0 +1,48 @@
import 'package:cheminova/models/user_model.dart';
import 'package:cheminova/services/api_client.dart';
import 'package:cheminova/services/api_urls.dart';
import 'package:cheminova/services/secure__storage_service.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
class UserProvider extends ChangeNotifier {
final _apiClient = ApiClient();
UserModel? _user;
bool _isLoading = false;
UserModel? get user => _user;
bool get isLoading => _isLoading;
void setLoading(bool loading) {
_isLoading = loading;
notifyListeners();
}
Future<void> fetchUserProfile() async {
setLoading(true);
try {
Response response = await _apiClient.get(
ApiUrls.profileUrl,
);
setLoading(false);
if (response.statusCode == 200) {
final data = response.data['myData'];
await SecureStorageService().write(key: 'user', value: data.toString());
_user = UserModel.fromJson(data);
notifyListeners();
} else {
throw Exception('Failed to load user profile');
}
} catch (e) {
setLoading(false);
throw Exception('Failed to load user profile: $e');
}
}
Future<void> clearUserProfile() async {
_user = null;
notifyListeners();
}
}

View File

@ -1,12 +1,12 @@
import 'package:cheminova/provider/login_provider.dart';
import 'package:cheminova/screens/password_change_screen.dart'; import 'package:cheminova/screens/password_change_screen.dart';
import 'package:cheminova/services/api_client.dart';
import 'package:cheminova/services/api_urls.dart';
import 'package:cheminova/widgets/common_app_bar.dart'; import 'package:cheminova/widgets/common_app_bar.dart';
import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/widgets/common_elevated_button.dart'; import 'package:cheminova/widgets/common_elevated_button.dart';
import 'package:cheminova/widgets/common_text_form_field.dart'; import 'package:cheminova/widgets/common_text_form_field.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../widgets/common_drawer.dart'; import '../widgets/common_drawer.dart';
class ChangePasswordPage extends StatefulWidget { class ChangePasswordPage extends StatefulWidget {
@ -19,130 +19,174 @@ class ChangePasswordPage extends StatefulWidget {
class _ChangePasswordPageState extends State<ChangePasswordPage> { class _ChangePasswordPageState extends State<ChangePasswordPage> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _oldPasswordController = TextEditingController();
final _newPasswordController = TextEditingController();
final _confirmPasswordController = TextEditingController();
bool _isLoading = false;
Future<(bool, String)> _changePassword() async {
if (_formKey.currentState!.validate()) {
setState(() {
_isLoading = true;
});
try {
final apiClient = ApiClient();
Response response =
await apiClient.put(ApiUrls.changePasswordUrl, data: {
'oldPassword': _oldPasswordController.text.trim(),
'newPassword': _newPasswordController.text.trim(),
'confirmPassword': _confirmPasswordController.text.trim(),
});
if (response.statusCode == 200) {
setState(() {
_isLoading = false;
});
return (true, response.data['message'].toString());
} else {
return (false, response.data['message'].toString());
}
} on DioException catch (e) {
setState(() {
_isLoading = false;
});
if (e.response?.data is Map<String, dynamic>) {
return (
false,
e.response?.data['message'].toString() ?? 'something went wrong'
);
} else if (e.response?.data is String) {
return (false, e.response?.data.toString() ?? 'something went wrong');
} else {
return (false, 'something went wrong');
}
} catch (e) {
setState(() {
_isLoading = false;
});
return (false, 'something went wrong');
}
} else {
return (false, 'something went wrong');
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CommonBackground( return CommonBackground(
isFullWidth: true, isFullWidth: true,
child: Scaffold( child: Scaffold(
drawer: const CommonDrawer(), drawer: const CommonDrawer(),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
appBar: CommonAppBar( appBar: CommonAppBar(
title: const Text(''),
title: const Text(''), backgroundColor: Colors.transparent,
backgroundColor: Colors.transparent, elevation: 0,
elevation: 0, actions: [
actions: [ IconButton(
IconButton( onPressed: () {
onPressed: () { Navigator.pop(context);
Navigator.pop(context); },
}, icon: Image.asset('assets/Back_attendance.png'),
icon: Image.asset('assets/Back_attendance.png'), padding: const EdgeInsets.only(right: 20),
padding: const EdgeInsets.only(right: 20), ),
), ],
], ),
), body: SingleChildScrollView(
body: SingleChildScrollView( child: Column(
child: Column( children: [
children: [ // const SizedBox(height: 50),
// const SizedBox(height: 50), // const SizedBox(height: 60),
// const SizedBox(height: 60), Container(
Container( padding:
padding: const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30),
const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30), margin: const EdgeInsets.symmetric(horizontal: 30.0),
margin: const EdgeInsets.symmetric(horizontal: 30.0), decoration: BoxDecoration(
decoration: BoxDecoration( border: Border.all(color: Colors.white),
border: Border.all(color: Colors.white), color: const Color(0xffB4D1E5).withOpacity(0.9),
color: const Color(0xffB4D1E5).withOpacity(0.9), borderRadius: BorderRadius.circular(26.0)),
borderRadius: BorderRadius.circular(26.0)), child: Form(
child: Form( key: _formKey,
key: _formKey, child: Column(
child: Column( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
children: <Widget>[ const SizedBox(height: 20),
const SizedBox(height: 20), const Text('Change Password',
const Text('Change Password', style: TextStyle(
style: TextStyle( fontSize: 30,
fontSize: 30, color: Colors.black,
color: Colors.black, fontWeight: FontWeight.w500,
fontWeight: FontWeight.w500, fontFamily: 'Roboto')),
fontFamily: 'Roboto')), const SizedBox(height: 20),
const SizedBox(height: 20), CommonTextFormField(
CommonTextFormField( controller: _oldPasswordController,
// controller: value.emailController, validator: (value) {
validator: (value) { if (value == null || value.isEmpty) {
if (value == null || value.isEmpty) { return 'Please enter your password';
return 'Please enter your email id'; }
} return null;
if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') },
.hasMatch(value)) { title: 'Current Password'),
return 'Please enter a valid email id'; const SizedBox(height: 20),
} CommonTextFormField(
return null; controller: _newPasswordController,
}, validator: (value) {
title: 'Current Password'), if (value == null || value.isEmpty) {
const SizedBox(height: 20), return 'Please enter your password';
CommonTextFormField( }
// controller: value.passwordController, return null;
validator: (value) { },
if (value == null || value.isEmpty) { title: 'New Password'),
return 'Please enter your password'; const SizedBox(height: 20),
} CommonTextFormField(
return null; controller: _confirmPasswordController,
}, validator: (value) {
title: 'New Password'), const SizedBox(height: 20), if (value == null || value.isEmpty) {
CommonTextFormField( return 'Please enter your password';
// controller: value.passwordController, }
validator: (value) { return null;
if (value == null || value.isEmpty) { },
return 'Please enter your password'; title: 'Confirm Password'),
} const SizedBox(height: 15),
return null; Align(
}, alignment: Alignment.center,
title: 'Confirm Password'), child: CommonElevatedButton(
const SizedBox(height: 15), backgroundColor: const Color(0xff004791),
Align( borderRadius: 30,
alignment: Alignment.center, width: double.infinity,
child: CommonElevatedButton( height: kToolbarHeight - 10,
backgroundColor: const Color(0xff004791), text: 'SIGN IN',
borderRadius: 30, isLoading: _isLoading,
width: double.infinity, onPressed: () {
height: kToolbarHeight - 10, _changePassword().then(
text: 'SIGN IN', (result) {
isLoading: false, var (status, message) = result;
onPressed: () { ScaffoldMessenger.of(context).showSnackBar(
Navigator.push(context, MaterialPageRoute(builder:(context) => const PasswordChangeScreen())); SnackBar(content: Text(message)));
}, if (status) {
// onPressed: value.isLoading Navigator.pushReplacement(
// ? null context,
// : () async { MaterialPageRoute(
// if (_formKey.currentState!.validate()) { builder: (context) =>
// value.login().then((result) { const PasswordChangeScreen(),
// var (status, message) = result; ),
// ScaffoldMessenger.of(context) );
// .showSnackBar(SnackBar( }
// content: Text(message))); },
// if (status) { );
// Navigator.pushReplacement( },
// context, ),
// MaterialPageRoute( )
// builder: (context) => ],
// const HomePage()));
// }
// });
// }
// },
))
],
),
), ),
), ),
], ),
), ],
)), ),
)),
); );
} }
} }

View File

@ -1,7 +1,9 @@
import 'package:cheminova/screens/verify_phone_screen.dart'; import 'package:cheminova/services/api_client.dart';
import 'package:cheminova/services/api_urls.dart';
import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/widgets/common_elevated_button.dart'; import 'package:cheminova/widgets/common_elevated_button.dart';
import 'package:cheminova/widgets/common_text_form_field.dart'; import 'package:cheminova/widgets/common_text_form_field.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ForgotPasswordScreen extends StatefulWidget { class ForgotPasswordScreen extends StatefulWidget {
@ -12,15 +14,87 @@ class ForgotPasswordScreen extends StatefulWidget {
} }
class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> { class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
bool isLoading = false;
void _submitEmail() {
if (_formKey.currentState!.validate()) {
// Process the form data
_forgetPassword();
}
}
Future<void> _forgetPassword() async {
setState(() {
isLoading = true;
});
try {
final apiClient = ApiClient();
Response response =
await apiClient.post(ApiUrls.forgetPasswordUrl, data: {
'email': _emailController.text.trim(),
});
if (response.statusCode == 200) {
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(response.data['message'].toString()),
),
);
Navigator.pop(context);
}
} on DioException catch (e) {
setState(() {
isLoading = false;
});
if (e.response?.data is Map<String, dynamic>) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.response?.data['message'].toString() ??
'Something went wrong'),
),
);
} else if (e.response?.data is String) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text(e.response?.data.toString() ?? 'Something went wrong'),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Something went wrong'),
),
);
}
}
setState(() {
isLoading = false;
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CommonBackground( return CommonBackground(
isFullWidth: false, isFullWidth: false,
child: Scaffold( child: Scaffold(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
appBar: AppBar(leading: InkWell(onTap:() { appBar: AppBar(
Navigator.pop(context); leading: InkWell(
},child: Image.asset('assets/Back_attendance.png')),backgroundColor: Colors.transparent,), onTap: () {
Navigator.pop(context);
},
child: Image.asset('assets/Back_attendance.png')),
backgroundColor: Colors.transparent,
),
body: Center( body: Center(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Container( child: Container(
@ -31,74 +105,86 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
color: const Color(0xffB4D1E5).withOpacity(0.9), color: const Color(0xffB4D1E5).withOpacity(0.9),
borderRadius: BorderRadius.circular(26.0), borderRadius: BorderRadius.circular(26.0),
), ),
child: Column( child: Form(
mainAxisSize: MainAxisSize.min, key: _formKey,
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min,
children: <Widget>[ crossAxisAlignment: CrossAxisAlignment.start,
Align( mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: Image.asset( child: Image.asset(
'assets/lock_logo2.png', 'assets/lock_logo2.png',
height: 50.0, // Adjust the height as needed height: 50.0, // Adjust the height as needed
width: 50.0, // Adjust the width as needed width: 50.0, // Adjust the width as needed
), ),
),
const Text(
'Forgot Password',
style: TextStyle(
fontSize: 30,
color: Colors.black,
fontWeight: FontWeight.w500,
fontFamily: 'Anek',
), ),
), const Text(
const Text( 'Forgot Password',
'Enter Registered Email ID to generate new password', style: TextStyle(
style: TextStyle( fontSize: 30,
fontSize: 14, color: Colors.black,
color: Colors.black, fontWeight: FontWeight.w500,
fontWeight: FontWeight.w300, fontFamily: 'Anek',
fontFamily: 'Roboto', ),
), ),
), const Text(
const SizedBox(height: 20), 'Enter Registered Email ID to generate new password',
const CommonTextFormField(title: ' Enter Your Email ID'), style: TextStyle(
const SizedBox(height: 20), fontSize: 14,
Align( color: Colors.black,
alignment: Alignment.center, fontWeight: FontWeight.w300,
child: TextButton( fontFamily: 'Roboto',
onPressed: () { ),
Navigator.pop(context); ),
const SizedBox(height: 20),
CommonTextFormField(
title: ' Enter Your Email ID',
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter your email id';
}
if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$')
.hasMatch(value)) {
return 'Please enter a valid email id';
}
return null;
}, },
child: const Text('Back to Login', controller: _emailController,
),
const SizedBox(height: 20),
Align(
alignment: Alignment.center,
child: TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text(
'Back to Login',
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
color: Colors.black, color: Colors.black,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
fontFamily: 'Roboto')), fontFamily: 'Roboto'),
),
),
), ),
), const SizedBox(height: 15),
const SizedBox(height: 15), Align(
Align( alignment: Alignment.center,
alignment: Alignment.center, child: CommonElevatedButton(
child: CommonElevatedButton( backgroundColor: const Color(0xff004791),
backgroundColor: const Color(0xff004791), borderRadius: 30,
borderRadius: 30, width: double.infinity,
width: double.infinity, isLoading: isLoading,
height: kToolbarHeight - 10, height: kToolbarHeight - 10,
text: 'SEND', text: 'SEND',
onPressed: () { onPressed: _submitEmail,
Navigator.push( ),
context,
MaterialPageRoute(
builder: (context) => const VerifyPhoneScreen(),
),
);
},
), ),
), ],
], ),
), ),
), ),
), ),

View File

@ -1,3 +1,4 @@
import 'package:cheminova/provider/user_provider.dart';
import 'package:cheminova/screens/calendar_screen.dart'; import 'package:cheminova/screens/calendar_screen.dart';
import 'package:cheminova/screens/collect_kyc_screen.dart'; import 'package:cheminova/screens/collect_kyc_screen.dart';
import 'package:cheminova/screens/mark_attendence_screen.dart'; import 'package:cheminova/screens/mark_attendence_screen.dart';
@ -12,38 +13,64 @@ import 'package:cheminova/widgets/common_drawer.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/screens/daily_tasks_screen.dart'; import 'package:cheminova/screens/daily_tasks_screen.dart';
import 'package:provider/provider.dart';
class HomePage extends StatelessWidget { class HomePage extends StatefulWidget {
const HomePage({super.key}); const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
Provider.of<UserProvider>(context, listen: false).fetchUserProfile();
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CommonBackground( return CommonBackground(
child: Scaffold( child: Scaffold(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
appBar: const CommonAppBar( appBar: AppBar(
title: Row( title: Row(
children: [ children: [
// CircleAvatar( // CircleAvatar(
// backgroundImage: AssetImage( // backgroundImage: AssetImage(
// 'assets/profile.png'), // Replace with actual user image // 'assets/profile.png'), // Replace with actual user image
// ), // ),
SizedBox(width: 10), const SizedBox(width: 10),
Column( Consumer<UserProvider>(
crossAxisAlignment: CrossAxisAlignment.start, builder: (context, userProvider, child) {
children: [ return Column(
Text('Welcome', crossAxisAlignment: CrossAxisAlignment.start,
style: TextStyle( children: [
const Text(
'Welcome',
style: TextStyle(
color: Colors.black87,
fontSize: 14,
fontWeight: FontWeight.w400),
),
Text(
userProvider.user?.name ?? 'User Name',
style: const TextStyle(
color: Colors.black87, color: Colors.black87,
fontSize: 14, fontSize: 20,
fontWeight: FontWeight.w400)), ),
Text('User Name', ),
style: TextStyle( ],
color: Colors.black87, fontSize: 20)), );
], },
), ),
], ],
), backgroundColor: Colors.transparent, elevation: 0, ),
backgroundColor: Colors.transparent,
elevation: 0,
), ),
drawer: const CommonDrawer(), drawer: const CommonDrawer(),
body: SafeArea( body: SafeArea(
@ -62,7 +89,8 @@ class HomePage extends StatelessWidget {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const MarkAttendanceScreen(), builder: (context) =>
const MarkAttendanceScreen(),
)); ));
}, },
), ),
@ -79,17 +107,23 @@ class HomePage extends StatelessWidget {
const SizedBox( const SizedBox(
height: 5, height: 5,
), ),
_buildCustomCard('Assign Tasks', '', onTap: () {}),
const SizedBox(
height: 5,
),
Row( Row(
children: [ children: [
Expanded( Expanded(
child: _buildCustomCard('Display\nSales data', child: _buildCustomCard(
'Quickly display Sales', onTap: () { 'Display\nSales data', 'Quickly display Sales',
Navigator.push( onTap: () {
context, Navigator.push(
MaterialPageRoute( context,
builder: (context) => const DisplaySalesScreen(), MaterialPageRoute(
)); builder: (context) =>
}), const DisplaySalesScreen(),
));
}),
), ),
const SizedBox( const SizedBox(
width: 12, width: 12,
@ -97,12 +131,13 @@ class HomePage extends StatelessWidget {
Expanded( Expanded(
child: _buildCustomCard('Update Inventory Data', child: _buildCustomCard('Update Inventory Data',
'Quickly Inventory Data', onTap: () { 'Quickly Inventory Data', onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const UpdateInventoryScreen(), builder: (context) =>
)); const UpdateInventoryScreen(),
}), ));
}),
), ),
], ],
), ),
@ -112,7 +147,8 @@ class HomePage extends StatelessWidget {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: _buildCustomCard('Summary', '\n\n', onTap: () { child:
_buildCustomCard('Summary', '\n\n', onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -125,11 +161,13 @@ class HomePage extends StatelessWidget {
), ),
Expanded( Expanded(
child: _buildCustomCard( child: _buildCustomCard(
'Product\nSales Data Visibility', '', onTap: () { 'Product\nSales Data Visibility', '',
onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const ProductSalesData(), builder: (context) =>
const ProductSalesData(),
)); ));
}), }),
), ),
@ -143,12 +181,13 @@ class HomePage extends StatelessWidget {
Expanded( Expanded(
child: _buildCustomCard('Collect \nKYC Data', child: _buildCustomCard('Collect \nKYC Data',
'Scan and upload KYC Documents', onTap: () { 'Scan and upload KYC Documents', onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const CollectKycScreen(), builder: (context) =>
)); const CollectKycScreen(),
}), ));
}),
), ),
], ],
), ),
@ -156,23 +195,33 @@ class HomePage extends StatelessWidget {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: _buildCustomCard('Notifications', child: _buildCustomCard(
'Tasks & Alerts\n\n', onTap: () { 'Notifications', 'Tasks & Alerts\n\n',
Navigator.push( onTap: () {
context, Navigator.push(
MaterialPageRoute( context,
builder: (context) => const NotificationScreen(), MaterialPageRoute(
)); builder: (context) =>
}), const NotificationScreen(),
));
}),
), ),
const SizedBox( const SizedBox(
width: 15, width: 15,
), ),
Expanded( Expanded(
child: _buildCustomCard('Calendar', child: _buildCustomCard(
' Upcoming Appointments & Deadlines',onTap: () { 'Calendar',
Navigator.push(context, MaterialPageRoute(builder: (context) => const CalendarScreen(),)); ' Upcoming Appointments & Deadlines',
},), onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const CalendarScreen(),
));
},
),
), ),
], ],
), ),
@ -180,14 +229,16 @@ class HomePage extends StatelessWidget {
Row( Row(
children: [ children: [
Expanded( Expanded(
child: _buildCustomCard('Products Manual', child: _buildCustomCard(
'details of products', onTap: () { 'Products Manual', 'details of products',
Navigator.push( onTap: () {
context, Navigator.push(
MaterialPageRoute( context,
builder: (context) => const ProductsManualScreen(), MaterialPageRoute(
)); builder: (context) =>
}), const ProductsManualScreen(),
));
}),
), ),
], ],
), ),
@ -202,7 +253,8 @@ class HomePage extends StatelessWidget {
); );
} }
Widget _buildCustomCard(String title, String subtitle, {void Function()? onTap}) { Widget _buildCustomCard(String title, String subtitle,
{void Function()? onTap}) {
return Container( return Container(
margin: const EdgeInsets.only(bottom: 10), margin: const EdgeInsets.only(bottom: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -222,9 +274,9 @@ class HomePage extends StatelessWidget {
), ),
subtitle: subtitle.isNotEmpty subtitle: subtitle.isNotEmpty
? Text( ? Text(
subtitle, subtitle,
style: const TextStyle(color: Colors.white70, fontSize: 13), style: const TextStyle(color: Colors.white70, fontSize: 13),
) )
: null, : null,
onTap: onTap, onTap: onTap,
), ),

View File

@ -1,5 +1,6 @@
import 'package:cheminova/provider/login_provider.dart'; import 'package:cheminova/provider/login_provider.dart';
import 'package:cheminova/screens/forgot_password_screen.dart'; import 'package:cheminova/screens/forgot_password_screen.dart';
import 'package:cheminova/screens/home_screen.dart';
import 'package:cheminova/screens/verify_phone_screen.dart'; import 'package:cheminova/screens/verify_phone_screen.dart';
import 'package:cheminova/widgets/common_background.dart'; import 'package:cheminova/widgets/common_background.dart';
import 'package:cheminova/widgets/common_elevated_button.dart'; import 'package:cheminova/widgets/common_elevated_button.dart';
@ -44,7 +45,10 @@ class _LoginPageState extends State<LoginPage> {
const SizedBox(height: 50), const SizedBox(height: 50),
Align( Align(
alignment: Alignment.center, alignment: Alignment.center,
child: Container(decoration: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(12)), child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12)),
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Image.asset('assets/cheminova_logo.png', child: Image.asset('assets/cheminova_logo.png',
height: kToolbarHeight - 25), height: kToolbarHeight - 25),
@ -54,7 +58,8 @@ class _LoginPageState extends State<LoginPage> {
Container( Container(
padding: padding:
const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30), const EdgeInsets.all(20.0).copyWith(top: 15, bottom: 30),
margin: const EdgeInsets.symmetric(horizontal: 30.0).copyWith(bottom: 50), margin: const EdgeInsets.symmetric(horizontal: 30.0)
.copyWith(bottom: 50),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all(color: Colors.white), border: Border.all(color: Colors.white),
color: const Color(0xffB4D1E5).withOpacity(0.9), color: const Color(0xffB4D1E5).withOpacity(0.9),
@ -81,20 +86,21 @@ class _LoginPageState extends State<LoginPage> {
fontFamily: 'Roboto')), fontFamily: 'Roboto')),
const SizedBox(height: 20), const SizedBox(height: 20),
Consumer<LoginProvider>( Consumer<LoginProvider>(
builder: (context, value, child) => builder: (context, value, child) =>
CommonTextFormField( CommonTextFormField(
controller: value.emailController, controller: value.emailController,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter your email id'; return 'Please enter your email id';
} }
if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') if (!RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$')
.hasMatch(value)) { .hasMatch(value)) {
return 'Please enter a valid email id'; return 'Please enter a valid email id';
} }
return null; return null;
}, },
title: 'Username')), title: 'Username'),
),
const SizedBox(height: 20), const SizedBox(height: 20),
Consumer<LoginProvider>( Consumer<LoginProvider>(
builder: (context, value, child) => builder: (context, value, child) =>
@ -108,7 +114,6 @@ class _LoginPageState extends State<LoginPage> {
}, },
title: 'Password')), title: 'Password')),
const SizedBox(height: 15), const SizedBox(height: 15),
Align( Align(
alignment: Alignment.center, alignment: Alignment.center,
child: TextButton( child: TextButton(
@ -140,7 +145,20 @@ class _LoginPageState extends State<LoginPage> {
text: 'SIGN IN', text: 'SIGN IN',
isLoading: value.isLoading, isLoading: value.isLoading,
onPressed: () { onPressed: () {
Navigator.push(context, MaterialPageRoute(builder:(context) => const VerifyPhoneScreen())); loginProvider.login().then((result) {
var (status, message) = result;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)));
if (status) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
const HomePage(),
),
);
}
});
}, },
// onPressed: value.isLoading // onPressed: value.isLoading
// ? null // ? null

View File

@ -1,5 +1,7 @@
import 'package:cheminova/constants/constant.dart'; import 'package:cheminova/constants/constant.dart';
import 'package:cheminova/screens/home_screen.dart';
import 'package:cheminova/screens/login_screen.dart'; import 'package:cheminova/screens/login_screen.dart';
import 'package:cheminova/services/secure__storage_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SplashScreen extends StatefulWidget { class SplashScreen extends StatefulWidget {
@ -10,12 +12,23 @@ class SplashScreen extends StatefulWidget {
} }
class _SplashScreenState extends State<SplashScreen> { class _SplashScreenState extends State<SplashScreen> {
void _checkLogin() {
SecureStorageService().read(key: 'user').then((value) {
if (value != null) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => const HomePage()));
} else {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => const LoginPage()));
}
});
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
Future.delayed(const Duration(seconds: 3), () { Future.delayed(const Duration(seconds: 3), () {
Navigator.pushReplacement( _checkLogin();
context, MaterialPageRoute(builder: (context) => const LoginPage()));
}); });
} }

View File

@ -1,7 +1,8 @@
class ApiUrls { class ApiUrls {
static const String baseUrl = static const String baseUrl = 'https://cheminova-api-2.onrender.com/api/';
'https://cheminova-api-2.onrender.com/api/'; static const String loginUrl = 'territorymanager/login';
static const String loginUrl = 'salescoordinator/login'; static const String profileUrl = 'territorymanager/my-profile';
static const String profileUrl = 'my-profile';
static const String markAttendanceUrl = 'v1/markattendance/salescoordinator'; static const String markAttendanceUrl = 'v1/markattendance/salescoordinator';
} static const String forgetPasswordUrl = 'territorymanager/forgot-password';
static const String changePasswordUrl = 'territorymanager/password/update';
}

View File

@ -1,7 +1,9 @@
import 'package:cheminova/provider/user_provider.dart';
import 'package:cheminova/screens/change_password_screen.dart'; import 'package:cheminova/screens/change_password_screen.dart';
import 'package:cheminova/screens/home_screen.dart'; import 'package:cheminova/screens/home_screen.dart';
import 'package:cheminova/screens/login_screen.dart'; import 'package:cheminova/screens/login_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CommonDrawer extends StatelessWidget { class CommonDrawer extends StatelessWidget {
const CommonDrawer({super.key}); const CommonDrawer({super.key});
@ -12,48 +14,58 @@ class CommonDrawer extends StatelessWidget {
child: ListView( child: ListView(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
children: <Widget>[ children: <Widget>[
Container( SizedBox(
height: 150, height: 150,
child: const DrawerHeader( child: DrawerHeader(
decoration: BoxDecoration( decoration: const BoxDecoration(
color: Colors.black87, color: Colors.black87,
), ),
child: Column( child: Consumer<UserProvider>(
crossAxisAlignment: CrossAxisAlignment.start,mainAxisAlignment: MainAxisAlignment.start, builder: (context, userProvider, child) {
children: [ if (userProvider.isLoading) {
Text( return const Center(child: CircularProgressIndicator());
'Username', } else if (userProvider.user != null) {
style: TextStyle( return Column(
color: Colors.white, crossAxisAlignment: CrossAxisAlignment.start,
fontSize: 18, mainAxisAlignment: MainAxisAlignment.start,
), children: [
),Text( Text(
'Employee ID', userProvider.user!.name,
style: TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 20, fontSize: 18,
), ),
), ),
], Text(
userProvider.user!.uniqueId,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
),
),
],
);
} else {
return const Text(
'No User Data',
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
);
}
},
), ),
), ),
), ),
// const UserAccountsDrawerHeader(
// accountName: Text("Name"),
// accountEmail: Text("Employee ID"),
// // currentAccountPicture: CircleAvatar(
// // backgroundImage: AssetImage(
// // 'assets/profile.png'), // Replace with actual user image
// // ),
// decoration: BoxDecoration(
// color: Colors.black87,
// ),
// ),
ListTile( ListTile(
leading: const Icon(Icons.home), leading: const Icon(Icons.home),
title: const Text('Home'), title: const Text('Home'),
onTap: () { onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const HomePage(),)); Navigator.push(
context,
MaterialPageRoute(builder: (context) => const HomePage()),
);
}, },
), ),
ListTile( ListTile(
@ -67,15 +79,25 @@ class CommonDrawer extends StatelessWidget {
leading: const Icon(Icons.settings), leading: const Icon(Icons.settings),
title: const Text('Change Password'), title: const Text('Change Password'),
onTap: () { onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangePasswordPage(),)); Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ChangePasswordPage()),
);
}, },
), ),
ListTile( ListTile(
leading: const Icon(Icons.exit_to_app), leading: const Icon(Icons.exit_to_app),
title: const Text('Logout'), title: const Text('Logout'),
onTap: () { onTap: () {
Navigator.pushReplacement(context, WidgetsBinding.instance.addPostFrameCallback((_) {
MaterialPageRoute(builder: (context) => const LoginPage())); Provider.of<UserProvider>(context, listen: false)
.clearUserProfile();
});
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const LoginPage()),
);
}, },
), ),
], ],

View File

@ -16,7 +16,8 @@ class CommonElevatedButton extends StatelessWidget {
this.borderRadius, this.borderRadius,
this.backgroundColor, this.backgroundColor,
this.height, this.height,
this.width, this.isLoading=false}); this.width,
this.isLoading = false});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -24,21 +25,22 @@ class CommonElevatedButton extends StatelessWidget {
height: height ?? kToolbarHeight - 25, height: height ?? kToolbarHeight - 25,
width: width ?? 200, width: width ?? 200,
child: ElevatedButton( child: ElevatedButton(
onPressed: onPressed, onPressed: isLoading ? null : onPressed,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius ?? 6)), borderRadius: BorderRadius.circular(borderRadius ?? 6)),
backgroundColor: backgroundColor ?? const Color(0xff1E1E1E), backgroundColor: backgroundColor ?? const Color(0xff1E1E1E),
side: const BorderSide(color: Colors.transparent)), side: const BorderSide(color: Colors.transparent)),
child: Center( child: Center(
child: isLoading?const CircularProgressIndicator( child: isLoading
backgroundColor: Colors.white, ? const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.black) backgroundColor: Colors.white,
):Text(text ?? 'Submit', valueColor: AlwaysStoppedAnimation<Color>(Colors.black))
style: const TextStyle( : Text(text ?? 'Submit',
fontSize: 15, style: const TextStyle(
color: Colors.white, fontSize: 15,
fontWeight: FontWeight.w400, color: Colors.white,
fontFamily: 'Anek'))))); fontWeight: FontWeight.w400,
fontFamily: 'Anek')))));
} }
} }

View File

@ -13,17 +13,19 @@ class CommonTextFormField extends StatelessWidget {
final List<TextInputFormatter>? inputFormatters; final List<TextInputFormatter>? inputFormatters;
final int? maxLength; final int? maxLength;
const CommonTextFormField( const CommonTextFormField({
{super.key, super.key,
required this.title, required this.title,
this.controller, this.controller,
this.validator, this.validator,
this.fillColor, this.fillColor,
this.readOnly, this.readOnly,
this.maxLines, this.maxLines,
this.height, this.height,
this.keyboardType, this.keyboardType,
this.inputFormatters, this.maxLength}); this.inputFormatters,
this.maxLength,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {