diff --git a/lib/api/api.dart b/lib/api/api.dart index 26d05a0..a6f62b1 100644 --- a/lib/api/api.dart +++ b/lib/api/api.dart @@ -31,3 +31,20 @@ Future registerPost({email, password, firstName, lastName}) async { ); return req.statusCode; } + +Future loginPost({email, password}) async { + Response req = await Dio().post( + (host + '/login'), + data: { + 'email': email, + 'password': password, + }, + options: Options( + contentType: Headers.formUrlEncodedContentType, + validateStatus: (status) { + return status! < 400; + }, + ), + ); + return req.statusCode; +} diff --git a/lib/components/login_error.dart b/lib/components/login_error.dart new file mode 100644 index 0000000..d8d6f5d --- /dev/null +++ b/lib/components/login_error.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:lottie/lottie.dart'; + +class LoginError extends StatefulWidget { + const LoginError({Key? key}) : super(key: key); + + @override + State createState() => LoginErrorState(); +} + +class LoginErrorState extends State { + @override + Widget build(BuildContext context) { + return SafeArea( + child: Container( + margin: const EdgeInsets.fromLTRB(10, 10, 10, 5), + child: Card( + color: const Color(0xff212226), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), + height: MediaQuery.of(context).size.height, + width: double.infinity, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + const SizedBox( + height: 50, + ), + const Text( + "Error", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 40), + ), + const SizedBox( + height: 45, + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Lottie.network( + "https://assets5.lottiefiles.com/temp/lf20_QYm9j9.json", + frameRate: FrameRate.max, + alignment: Alignment.center, + height: 350, + fit: BoxFit.fitHeight, + ), + ], + ), + const SizedBox( + height: 70, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Text( + "An error has occured\nMake sure to check\nif your email has been \nregistered before.", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 25), + ), + ], + ) + ], + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/components/login_form.dart b/lib/components/login_form.dart new file mode 100644 index 0000000..6bb8475 --- /dev/null +++ b/lib/components/login_form.dart @@ -0,0 +1,212 @@ +import 'package:flutter/material.dart'; +import 'package:lottie/lottie.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:nekoya_flutter/api/api.dart'; +import 'package:nekoya_flutter/components/login_error.dart'; +import 'package:nekoya_flutter/components/login_verify.dart'; + +class LoginForm extends StatefulWidget { + const LoginForm({Key? key}) : super(key: key); + + @override + State createState() => LoginFormState(); +} + +final _formKey = GlobalKey(); + +class LoginFormState extends State { + @override + Widget build(BuildContext context) { + return SafeArea( + child: Container( + margin: const EdgeInsets.fromLTRB(10, 10, 10, 5), + child: Card( + color: const Color(0xff212226), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: SingleChildScrollView( + child: Container( + transform: Matrix4.translationValues(0, -35, 0), + padding: const EdgeInsets.fromLTRB(10, 20, 10, 0), + height: MediaQuery.of(context).size.height, + width: double.infinity, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Lottie.network( + "https://assets3.lottiefiles.com/packages/lf20_myor1trh.json", + frameRate: FrameRate.max, + alignment: Alignment.center, + fit: BoxFit.fitHeight, + height: 250, + ), + ], + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 25), + child: FormBuilder( + key: _formKey, + child: Column( + children: [ + makeInput(label: "Email"), + makeInput(label: "Password", obscureText: true) + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 35), + child: Container( + padding: const EdgeInsets.only(top: 3, left: 3), + child: MaterialButton( + minWidth: double.infinity, + height: 35, + onPressed: () async { + if (_formKey.currentState! + .fields["Email Address"]!.value == + '' || + _formKey.currentState!.fields["Password"]! + .value == + '') { + showAlertDialog(context); + } else { + var statusCode = await loginPost( + email: _formKey.currentState! + .fields["Email Address"]!.value, + password: _formKey.currentState! + .fields["Password"]!.value); + + if (statusCode == 200) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LoginVerify())); + } else { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const LoginError())); + } + } + }, + color: const Color(0xff8B0000), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(40)), + child: const Text( + "Login", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 15, + ), + ), + ), + ), + ), + const SizedBox( + height: 5, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Text( + "Don't have an account ?? \nClick here to Sign Up !!", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 15), + ), + ], + ) + ], + ), + ], + ), + ), + ), + ), + ), + ); + } +} + +Widget makeInput({label, obscureText = false}) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: const TextStyle( + fontSize: 12, fontWeight: FontWeight.bold, color: Colors.white), + ), + const SizedBox( + height: 5, + ), + FormBuilderTextField( + initialValue: "", + name: label, + obscureText: obscureText, + style: const TextStyle(color: Colors.white), + decoration: const InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.red, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white, + ), + ), + border: + OutlineInputBorder(borderSide: BorderSide(color: Colors.white)), + ), + ), + const SizedBox( + height: 10, + ) + ], + ); +} + +showAlertDialog(BuildContext context) { + Widget okButton = TextButton( + child: const Text("OK", style: TextStyle(color: Colors.red)), + onPressed: () { + Navigator.of(context, rootNavigator: true).pop(); + }, + ); + AlertDialog alert = AlertDialog( + backgroundColor: const Color(0xff1b1c1e), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + title: const Text( + "Error", + style: TextStyle(color: Colors.white), + ), + content: const Text( + "Make sure to fill all text fields", + style: TextStyle(color: Colors.white70), + ), + actions: [ + okButton, + ], + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alert; + }, + ); +} diff --git a/lib/components/login_verify.dart b/lib/components/login_verify.dart new file mode 100644 index 0000000..bd04e9b --- /dev/null +++ b/lib/components/login_verify.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:lottie/lottie.dart'; + +class LoginVerify extends StatefulWidget { + const LoginVerify({Key? key}) : super(key: key); + + @override + State createState() => LoginVerifyState(); +} + +class LoginVerifyState extends State { + @override + Widget build(BuildContext context) { + return SafeArea( + child: Container( + margin: const EdgeInsets.fromLTRB(10, 10, 10, 5), + child: Card( + color: const Color(0xff212226), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + child: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), + height: MediaQuery.of(context).size.height, + width: double.infinity, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + const SizedBox( + height: 50, + ), + const Text( + "Verify Your Email Address", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 40), + ), + const SizedBox( + height: 45, + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Lottie.network( + "https://assets1.lottiefiles.com/packages/lf20_IUWMcw.json", + frameRate: FrameRate.max, + alignment: Alignment.center, + height: 350, + fit: BoxFit.fitHeight, + ), + ], + ), + const SizedBox( + height: 75, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Text( + "Before proceeding,\n please check your email\n for a verification link to verify \nyour email address.", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 20), + ), + ], + ) + ], + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/components/menu.dart b/lib/components/menu.dart index e8e5851..4d74b63 100644 --- a/lib/components/menu.dart +++ b/lib/components/menu.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:nekoya_flutter/screens/login.dart'; import 'dart:math' as math; import 'package:nekoya_flutter/screens/products.dart'; @@ -45,7 +46,7 @@ class _MenuState extends State { setState(() { _selectedIndex = index; if (index == 0) { - _selectedWidget = const Products(); + _selectedWidget = const Login(); } else if (index == 1) { _selectedWidget = const Products(); } else if (index == 2) { diff --git a/lib/screens/login.dart b/lib/screens/login.dart new file mode 100644 index 0000000..c902137 --- /dev/null +++ b/lib/screens/login.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:nekoya_flutter/components/login_form.dart'; + +class Login extends StatefulWidget { + const Login({Key? key}) : super(key: key); + + @override + State createState() => _LoginState(); +} + +class _LoginState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xff1b1c1e), + appBar: AppBar( + title: const Text('Login'), + centerTitle: true, + backgroundColor: const Color(0xff212226), + ), + body: const LoginForm()); + } +}